Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter centralized/common loading screen for entire Application

I am working in Riverpod Auth flow boilerplate application.

I want to use common loading screen for all async function even login and logout. Currently I have AppState provider if Appstate loading i show loading screen. it's working fine for login but i wonder it’s good way or bad way.

Can i use this loading screen for all async task in the App?

AuthWidget:

class AuthWidget extends ConsumerWidget {
  const AuthWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    AppState appState = ref.watch(appStateProvider);

    if(appState.isLoading){
      return const Center(child: CircularProgressIndicator(color: Colors.red),);
    }
    return appState.isAuthenticated ? const HomePage() : const SignIn();
  }
}

AppState:

class AppState {
  User? user;
  bool isLoading;
  bool isAuthenticated;

  AppState(this.user, this.isLoading, this.isAuthenticated);

}

AuthRepository:

class AuthRepository extends StateNotifier<AppState>{

  AuthRepository() : super(AppState(null,false,false));

  Future<void> signIn()async {
    state = AppState(null,true,false);

    await Future.delayed(const Duration(seconds: 3));
    User user = User(userName: 'FakeUser', email: '[email protected]');
    AppState appState = AppState(user, false, true);
    state = appState;
  }

}

final appStateProvider = StateNotifierProvider<AuthRepository,AppState>((ref){
  return AuthRepository();
});
like image 224
yathavan Avatar asked Aug 06 '26 06:08

yathavan


1 Answers

To answer your question : Yes you can.

The only thing I'd change here is the content of your AppState : I'd use a LoadingState dedicated to trigger your Loader instead.

Here is how I like to manage screens with a common loader in my apps.

1 - Create a LoadingState and provide it

final loadingStateProvider = ChangeNotifierProvider((ref) => LoadingState());

class LoadingState extends ChangeNotifier {
  bool isLoading = false;

  void startLoader() {
    if (!isLoading) {
      isLoading = true;
      notifyListeners();
    }
  }

  void stopLoader() {
    if (isLoading) {
      isLoading = false;
      notifyListeners();
    }
  }
}

2 - Define a base page with the "common" loader

class LoadingContainer extends ConsumerWidget {
  const LoadingContainer({
    Key? key,
    required this.child,
  }) : super(key: key);

  final Widget child;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final state = ref.watch(loadingStateProvider);
    return Stack(
      children: [
        child,
        if (state.isLoading)
          const Center(child: CircularProgressIndicator())
        else
          const SizedBox(),
      ],
    );
  }
}

3 - Implement this widget whenever I need to handle loading datas.

return Scaffold(
      backgroundColor: AppColor.blue,
      body: LoadingContainer(
        child: ...

And then I simply have to update my loadingStateProvider and it's isLoading value from a Controller or the Widget directly

like image 81
FDuhen Avatar answered Aug 08 '26 20:08

FDuhen