skip to Main Content

Maybe I am approaching it the wrong way… I intend to adapt the Home Screen to the user data that I find locally stored. So I create a BLoC, check the local DB, then (in coding aka widget order) I create a MaterialApp with the Home Screen based on the data I found.

class App extends StatelessWidget {
  const App({
    super.key,
    required this.appDataRepository});

  final AppDataRepository appDataRepository;

  @override
  Widget build(BuildContext context) {
    return MultiRepositoryProvider(
      providers: [
        RepositoryProvider.value(
            value: appDataRepository)
      ],
      child: BlocProvider(
        create: (_) => AppBloc(GetUserUC(clientRepository, operatorRepository))..add(AppLaunched()),
        child: const AppView(),
      ),


    );
  }
}

class AppView extends StatelessWidget {
  const AppView({super.key});

  @override
  Widget build(BuildContext context) {
    final AppState state = context.read<AppBloc>().state;
print('app state ${state.role.name} ${state.startPage}');
    return MaterialApp(
      theme: MobileTheme.light,
      darkTheme: MobileTheme.dark,
      home: state.startPage == StartPage.selectRole
       ? const UserDataPage()
        : state.startPage == StartPage.clientHome
          ? const HomePageClient()
          : state.startPage == StartPage.operatorHome
            ? const HomePageOperator()
            : const HomePageClient(), //TODO
    );
  }
}

In my BLoC there is also a print command which shows that in timely order the MaterialApp is build before BLoC fetches the data and yields a new state.

How would I best wait for the state update to come before initializing the MaterialApp. Somehow I can hardly think of anything elegant with a FutureBuilder. Or is there a completely different approach that makes more sense?

2

Answers


  1. You should initialize the material app in the App Class.

    After that in the AppView, you can go for a Splash Screen or a Loading Screen

    Then you should wrap the body of the AppView with a Bloc Listener and then inside the Bloc Listener, according to the state change you can navigate where ever you want in your app.

    Login or Signup to reply.
  2. With bloc you can handle all state management in the bloc and provide states depending on the current state to your page (like you did in your code snippet).

    And in the same way you can also build a kind of "loading", or "waiting" page when waiting for the bloc to do some work.

    The "MaterialApp" widget and other widgets should then be put above your page.

    I put together a small example that should show the initialization of a bloc with the page rebuilding.

    You can run the following example directly as it is:

    import 'package:flutter/material.dart';
    import 'package:flutter_bloc/flutter_bloc.dart';
    
    // to run it in dartpad.dev
    void main() => runApp(const MaterialApp(home: Scaffold(body: BlocPage(100))));
    
    class BlocPage extends StatelessWidget {
      final int someBlocPageData;
    
      const BlocPage(this.someBlocPageData);
    
      @override
      Widget build(BuildContext context) {
        return BlocProvider<SomeBloc>(
          create: (BuildContext context) => SomeBloc()..add(BlocInitEvent(data: someBlocPageData)),
          child: BlocBuilder<SomeBloc, SomeState>(builder: _buildWithState),
        );
      }
    
      Widget _buildWithState(BuildContext context, SomeState state) {
        if (state is SomeStateInitialized) {
          return Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              ElevatedButton(
                onPressed: () => BlocProvider.of<SomeBloc>(context).add(BlocChangeEvent()),
                child: Text("Change bloc state ${state.data}"),
              ),
              ElevatedButton(
                onPressed: () => BlocProvider.of<SomeBloc>(context).add(BlocInitEvent(data: someBlocPageData)),
                child: const Text("Simulate New App Start"),
              ),
            ],
          );
        } else {
          return const Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Center(child: Text("LOADING...")),
            ],
          );
        }
      }
    }
    
    class SomeBloc extends Bloc<SomeEvent, SomeState> {
      late int _data;
    
      SomeBloc() : super(SomeState()) {
        on<BlocInitEvent>(_handleBlocInit);
        on<BlocChangeEvent>(_handleBlocStateChange);
      }
    
      Future<void> _handleBlocInit(BlocInitEvent event, Emitter<SomeState> emit) async {
        emit(SomeState()); // only needed for the example "simulate new app start"
        await Future<void>.delayed(const Duration(seconds: 4)); // simulate waiting...
        _data = event.data;
        emit(SomeStateInitialized(data: _data));
      }
    
      Future<void> _handleBlocStateChange(BlocChangeEvent event, Emitter<SomeState> emit) async {
        emit(SomeStateInitialized(data: ++_data));
      }
    
      @mustCallSuper
      @override
      Future<void> close() async {
        return super.close();
      }
    }
    
    class SomeState {
      @override
      bool operator ==(Object other) => other is SomeState && other.runtimeType == runtimeType;
    }
    
    class SomeStateInitialized extends SomeState {
      final int data;
    
      SomeStateInitialized({required this.data});
    
      @override
      bool operator ==(Object other) =>
          other is SomeStateInitialized && other.runtimeType == runtimeType && data == other.data;
    }
    
    class SomeEvent {}
    
    class BlocChangeEvent extends SomeEvent {}
    
    class BlocInitEvent extends SomeEvent {
      final int data;
    
      BlocInitEvent({required this.data});
    }
    

    In the same way you can of course also load some data inside of the bloc, show some kind of loading page state during it and then navigate to another page as soon as the data is loaded (by providing a new state with the data, or using the navigator inside of the bloc with a shared build context). The new Page could then also accept a parameter for the data, etc…

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search