← Docs
Recipe

Flutter patterns

Reusable widget architectures and state management recipes for production Flutter apps.

BLoC + freezed

Combine the BLoC library with freezed unions for exhaustive state handling. Define events, states, and a bloc class that maps events to async state transitions.

abstract class AuthEvent {}
class LoginRequested extends AuthEvent {
  final String email;
  final String password;
  const LoginRequested(this.email, this.password);
}

@freezed
class AuthState with _$AuthState {
  const factory AuthState.initial() = _Initial;
  const factory AuthState.loading() = _Loading;
  const factory AuthState.authenticated(User user) = _Authenticated;
  const factory AuthState.failure(String message) = _Failure;
}

Riverpod providers

Use Riverpod for compile-safe dependency injection. Prefer StateNotifierProvider for mutable state and FutureProvider for async data fetching.

final authProvider = StateNotifierProvider<AuthNotifier, AuthState>((ref) {
  return AuthNotifier(ref.read(authRepositoryProvider));
});

final userStreamProvider = StreamProvider<User?>((ref) {
  return ref.watch(authProvider.notifier).userStream;
});

Widget layering

Compose screens from small, single-purpose widgets. Extract layout, loading, error, and empty states into dedicated widgets to keep build methods under 50 lines.

  • AsyncValueWidget — maps AsyncValue to loading/data/error
  • ResponsiveLayout — switches between mobile and desktop scaffolds
  • SliverAppBarDelegate — reusable collapsing header behavior

Navigation 2.0 with GoRouter

Declare typed routes with path parameters and redirect guards. GoRouter handles deep linking and browser back-button support out of the box.

final router = GoRouter(
  initialLocation: '/login',
  redirect: (context, state) {
    final loggedIn = AuthScope.of(context).isAuthenticated;
    if (!loggedIn && state.matchedLocation != '/login') return '/login';
    return null;
  },
  routes: [
    GoRoute(path: '/login', builder: (_, __) => const LoginScreen()),
    GoRoute(path: '/home', builder: (_, __) => const HomeScreen()),
  ],
);

These patterns ship in Meridian's Flutter SDK. See the Flutter SDK reference for integration details.