Home > OS >  How to fix eternal loading when fetching data in flutter?
How to fix eternal loading when fetching data in flutter?

Time:11-28

I am trying to make sign in in dart using cubit/bloc.

And when I try to change state of my cubit(auth) to Waiting => CircularProgressIndicator

It looks like this

Then my app is getting stuck when api returns statusCode == 400 and I call another emit to show dialog window

But if sign in is successful(statusCode == 200) then everything is ok, and I navigate to main_page.dart

How to fix this problem and transfer data reponse from api to widget(I want to send statusCode and message to widget)

My cubit file:

class AuthCubit extends Cubit<AuthState> {
  AuthCubit() : super(AuthState(
    email: "",
    password: "",
  ));

  final ApiService _apiService = ApiService();

  void setEmail(String email) => emit(state.copyWith(email: email));
  void setPassword(String password) => emit(state.copyWith(password: password));

  Future signIn() async {
    emit(WaitingSignInAuth(state.email, state.password));
    try {
      final data = await _apiService.signIn(
        email: state.email ?? "",
        password: state.password ?? ""
      );
      if (data['success']) {
        print(data);
        emit(const SuccessAutentification());
      }
    } on DioError catch (ex) {
      print(ex.toString());
      //I want to transfer to ErrorSignInAuth ex.response!.data['message'] but I don't know how 
      emit(ErrorSignInAuth(state.email, state.password));
    } catch (e) {
      print(e);
    }
  }
}

This is my state file:

class AuthState extends Equatable {
  final String? email;
  final String? password;

  const AuthState({
    this.email,
    this.password,
  });

  AuthState copyWith({
    String? email,
    String? password,
  }) {
    return AuthState(
      email: email ?? this.email,
      password: password ?? this.password,
    );
  }

  @override
  List<Object?> get props =>
      [email, password];
}

class SuccessAutentification extends AuthState {
  const SuccessAutentification() : super();
}

class WaitingSignInAuth extends AuthState {
  const WaitingSignInAuth(email, password) : super(email: email, password: password);
}

class ErrorSignInAuth extends AuthState {
  const ErrorSignInAuth(email, password) : super(email: email, password: password);
}

And this is the widget where I use this cubit:

@override
  Widget build(BuildContext context) {
    return BlocConsumer<AuthCubit, AuthState>(
      listener: (context, state) {
        if (state is WaitingSignInAuth) {
          showDialog(
              context: context,
              builder: (context) => Container(
                width: MediaQuery.of(context).size.width,
                height: MediaQuery.of(context).size.height,
                color: Colors.black.withOpacity(0.6),
                  child: const Center(
                    child: CircularProgressIndicator(
                      strokeWidth: 1,
                      color: Colors.black,
                      backgroundColor: Colors.white,
                    ),
                  ),
                ));
        }
        if (state is SuccessAutentification) {
          Navigator.of(context).pushReplacement(
            MaterialPageRoute(
              builder: (_) => const MainWidget(),
            ),
          );
        }
        if (state is ErrorAuthentification) {
          showDialog(
            context: context,
            builder: (BuildContext context) {
              return AlertDialog(
                title: Text("Bad request"),
                content: SingleChildScrollView(
                  child: ListBody(
                    children: <Widget>[
                      Text("Error") // I want to show here error message
                    ],
                  ),
                ),
                actions: <Widget>[
                  TextButton(
                    child: const Text("Close"),
                    onPressed: () {
                      Navigator.of(context).pop();
                    },
                  )
                ],
              );
            }
          );
        }
      },
      builder: (context, state) {
        return Scaffold(
          LoginButton(
            color: _isValid ? AppColors.white : AppColors.whiteA3A3A3,
            text: "Login in",
            textColor: Colors.black,
            isButtonDisabled: _isValid ? false : true,
            onPressed: () {
              if (_key.currentState!.validate()) {
                BlocProvider.of<AuthCubit>(context).setEmail(_email.text.trim());
                BlocProvider.of<AuthCubit>(context).setPassword(_password.text.trim());
                BlocProvider.of<AuthCubit>(context).signIn();
                _key.currentState!.save();
              }
            },
          )
        );
      },
    );
  }

CodePudding user response:

In signIn() function, after you emit WaitingSignInAuth state, in some cases you are not emitting any other state, so your page is always loading.

Future signIn() async {
  emit(WaitingSignInAuth(state.email, state.password));
  try {
    final data = await _apiService.signIn(
        email: state.email ?? "",
        password: state.password ?? ""
    );
    if (data['success']) {
      print(data);
      emit(const SuccessAutentification());
    } else {
      // emit state
      emit(ErrorSignInAuth(state.email, state.password));
    }
  } on DioError catch (ex) {
    print(ex.toString());
    emit(ErrorSignInAuth(state.email, state.password));
  } catch (e) {
    print(e);
    // emit state
    emit(ErrorSignInAuth(state.email, state.password));
  }
}
  • Related