Fluent bloc user login

Posted by silrayn on Sat, 19 Feb 2022 20:07:04 +0100

[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-xsljaswk-1620260140025)( https://ducafecat.tech/2021/05/06/translation/mastering-flutter-bloc-pattern-for-login-part-1/2021-05-06-08-01-18.png )]

original text

https://medium.com/theotherdev-s/mastering-flutter-bloc-pattern-for-login-part-1-94082e139725

preface

First of all, since this is not a basic tutorial, we take it for granted that this is a route knowledge. We also include a little bit of validation and formoz packages to create reusable models; This is not the purpose of this tutorial to show how this will work, as you will see in the next tutorial. For the login section, we also used a subset of bloc (cube) for tutorial purposes, so you will see the difference between the two.

Code, you can read the code first and then read the document

https://github.com/Alessandro-v/bloc_login

reference resources

  • https://pub.flutter-io.cn/packages/equatable
  • https://pub.flutter-io.cn/packages/validation
  • https://pub.flutter-io.cn/packages/flutter_bloc
  • https://pub.flutter-io.cn/packages/formoz

text

start

Before we start, let's go to pubspec Add some necessary packages to yaml:

equatable: ^2.0.0
flutter_bloc: ^7.0.0
formz: ^0.3.2

Adding an equatable package will only make your work easier, but if you want to manually compare instances of classes, you just need to rewrite "= =" and hashCode.

Login status

Let's start with a class that contains form states and all field states:

class LoginState extends Equatable {
  const LoginState({
    this.email = const Email.pure(),
    this.password = const Password.pure(),
    this.status = FormzStatus.pure,
    this.exceptionError,
  });
  final Email email;
  final Password password;
  final FormzStatus status;
  final String exceptionError;
  @override
  List<Object> get props => [email, password, status, exceptionError];
  LoginState copyWith({
    Email email,
    Password password,
    FormzStatus status,
    String error,
  }) {
    return LoginState(
      email: email ?? this.email,
      password: password ?? this.password,
      status: status ?? this.status,
      exceptionError: error ?? this.exceptionError,
    );
  }
}

Now let's create our LoginCubit, which will be responsible for executing logic, such as getting email and outputting new status through emit:

class LoginCubit extends Cubit<LoginState> {
  LoginCubit() : super(const LoginState());
  void emailChanged(String value) {
    final email = Email.dirty(value);
    emit(state.copyWith(
      email: email,
      status: Formz.validate([
        email,
        state.password
      ]),
    ));
  }
  void passwordChanged(String value) {
    final password = Password.dirty(value);
    emit(state.copyWith(
      password: password,
      status: Formz.validate([
        state.email,
        password
      ]),
    ));
  }
  Future<void> logInWithCredentials() async {
    if (!state.status.isValidated) return;
    emit(state.copyWith(status: FormzStatus.submissionInProgress));
    try {
      await Future.delayed(Duration(milliseconds: 500));
      emit(state.copyWith(status: FormzStatus.submissionSuccess));
    } on Exception catch (e) {
      emit(state.copyWith(status: FormzStatus.submissionFailure, error: e.toString()));
    }
  }
}

But how do we connect the wrist ruler to our user interface? The following is the rescue of BlocProvider. This is a widget that uses: BlocProvider Of < logincubit > (context) provides a block for its subcomponents

BlocProvider(
  create: (_) => LoginCubit(),
  child: LoginForm(),
),

Login form

Now that it seems to be in his own place, it's time to solve our last puzzle, the whole user interface

class LoginForm extends StatelessWidget {
  const LoginForm({Key key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return BlocConsumer<LoginCubit, LoginState>(
        listener: (context, state) {
          if (state.status.isSubmissionFailure) {
            print('submission failure');
          } else if (state.status.isSubmissionSuccess) {
            print('success');
          }
        },
        builder: (context, state) => Stack(
          children: [
            Positioned.fill(
              child: SingleChildScrollView(
                padding: const EdgeInsets.fromLTRB(38.0, 0, 38.0, 8.0),
                child: Container(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    mainAxisAlignment: MainAxisAlignment.start,
                    children: [
                      _WelcomeText(),
                      _EmailInputField(),
                      _PasswordInputField(),
                      _LoginButton(),
                      _SignUpButton(),
                    ],
                  ),
                ),
              ),
            ),
            state.status.isSubmissionInProgress
                ? Positioned(
              child: Align(
                alignment: Alignment.center,
                child: CircularProgressIndicator(),
              ),
            ) : Container(),
          ],
        )
    );
  }
}

In order to respond to the new state sent by Cubit, we need to wrap our form in a BlocConsumer. Now we will expose a listener and a builder.

  • Listener

Here we will listen for state changes, such as displaying errors or performing navigation in response to API calls.

  • Builder

Here, we will show the change of ui reaction state, our Cubit.

user interface

Our user interface consists of a column and five sub elements, but we only show two short widgets:

class _EmailInputField extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocBuilder<LoginCubit, LoginState>(
      buildWhen: (previous, current) => previous.email != current.email,
      builder: (context, state) {
        return AuthTextField(
          hint: 'Email',
          key: const Key('loginForm_emailInput_textField'),
          keyboardType: TextInputType.emailAddress,
          error: state.email.error.name,
          onChanged: (email) => context
              .read<LoginCubit>()
              .emailChanged(email),
        );
      },
    );
  }
}
class _LoginButton extends StatelessWidget {
  const _LoginButton({Key key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return BlocBuilder<LoginCubit, LoginState>(
      buildWhen: (previous, current) => previous.status != current.status,
      builder: (context, state) {
        return CupertinoButton(
            child: Text('Login'),
            onPressed: state.status.isValidated
                ? () => context.read<LoginCubit>().logInWithCredentials()
                : null
        );
      },
    );
  }
}

Both widgets are packaged in a BlocBuilder, which is responsible for rebuilding them only when the elbow sends a new status for their respective evaluation properties, so, for example, if the user doesn't type anything in the email field, the EmailInputField will never be rebuilt.

Conversely, if all fields are verified, the button will call the logInWithCredentials() function, which will issue a new status (failure or success) based on the API response.

The old fellow can remember the praise and forwarding, and I will be more motivated to present Flutter good Wen ~ ~.

© Cat brother

https://ducafecat.tech/

https://github.com/ducafecat

Previous period

Open Source

GetX Quick Start

https://github.com/ducafecat/getx_quick_start

News client

https://github.com/ducafecat/flutter_learn_news

Translation of strapi manual

https://getstrapi.cn

Wechat discussion group ducafecat

Series collection

translation

https://ducafecat.tech/categories/%E8%AF%91%E6%96%87/

Fundamentals of Dart programming language

https://space.bilibili.com/404904528/channel/detail?cid=111585

Introduction to Flutter zero Foundation

https://space.bilibili.com/404904528/channel/detail?cid=123470

Actual combat of Flutter starts from scratch news client

https://space.bilibili.com/404904528/channel/detail?cid=106755

Fluent component development

https://space.bilibili.com/404904528/channel/detail?cid=144262

Flutter Bloc

https://space.bilibili.com/404904528/channel/detail?cid=177519

Flutter Getx4

https://space.bilibili.com/404904528/channel/detail?cid=177514

Docker Yapi

https://space.bilibili.com/404904528/channel/detail?cid=130578

Topics: Flutter