Skip to content

Commit 78a3337

Browse files
committed
refactor(app): improve app state management and naming
- Rename AppStatus to AppLifeCycleStatus for clarity - Update enum values to better reflect their purpose - Adjust AppState class to use new AppLifeCycleStatus - Update related imports and usages across multiple files
1 parent 6390016 commit 78a3337

File tree

5 files changed

+101
-91
lines changed

5 files changed

+101
-91
lines changed

lib/account/view/account_page.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class AccountPage extends StatelessWidget {
2323
final appState = context.watch<AppBloc>().state;
2424
final user = appState.user;
2525
final status = appState.status;
26-
final isAnonymous = status == AppStatus.anonymous;
26+
final isAnonymous = status == AppLifeCycleStatus.anonymous;
2727
final theme = Theme.of(context);
2828
final textTheme = theme.textTheme;
2929

lib/app/bloc/app_state.dart

Lines changed: 88 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,137 @@
11
part of 'app_bloc.dart';
22

3-
/// Represents the application's authentication status.
4-
enum AppStatus {
5-
/// The application is initializing and the status is unknown.
6-
initial,
3+
/// Defines the various statuses of the application's overall state.
4+
///
5+
/// This enum helps manage the application's flow, especially during startup
6+
/// and critical operations like fetching remote configuration or handling
7+
/// authentication changes.
8+
enum AppLifeCycleStatus {
9+
/// The application is in the initial phase of bootstrapping,
10+
/// fetching remote configuration and user settings.
11+
initializing,
12+
13+
/// The user is not authenticated.
14+
unauthenticated,
715

8-
/// The user is authenticated.
16+
/// The user is authenticated (e.g., standard user).
917
authenticated,
1018

11-
/// The user is unauthenticated.
12-
unauthenticated,
13-
14-
/// The user is anonymous (signed in using an anonymous provider).
19+
/// The user is anonymous (e.g., guest user).
1520
anonymous,
1621

17-
/// Fetching the essential RemoteConfig.
22+
/// The application is currently fetching remote configuration.
23+
/// This status is used for re-fetching or background checks, not initial load.
1824
configFetching,
1925

20-
/// Fetching the essential RemoteConfig failed.
26+
/// The application failed to fetch remote configuration.
2127
configFetchFailed,
2228

23-
/// A new version of the app is required.
24-
updateRequired,
25-
26-
/// The app is currently under maintenance.
29+
/// The application is currently under maintenance.
2730
underMaintenance,
31+
32+
/// A mandatory update is required for the application.
33+
updateRequired,
2834
}
2935

36+
/// {@template app_state}
37+
/// Represents the overall state of the application.
38+
///
39+
/// This state includes authentication status, user settings, remote
40+
/// configuration, and UI-related preferences.
41+
/// {@endtemplate}
3042
class AppState extends Equatable {
3143
/// {@macro app_state}
3244
const AppState({
45+
required this.status,
3346
required this.settings,
34-
required this.selectedBottomNavigationIndex,
35-
this.themeMode = ThemeMode.system,
36-
this.appTextScaleFactor = AppTextScaleFactor.medium,
37-
this.flexScheme = FlexScheme.material,
38-
this.fontFamily,
39-
this.status = AppStatus.initial, // Changed from AppStatus
47+
required this.environment,
4048
this.user,
41-
this.locale = const Locale('en'), // Default to English
4249
this.remoteConfig,
43-
this.environment,
50+
this.themeMode = ThemeMode.system,
51+
this.flexScheme = FlexScheme.blue,
52+
this.fontFamily,
53+
this.appTextScaleFactor = AppTextScaleFactor.medium,
54+
this.selectedBottomNavigationIndex = 0,
55+
this.locale,
4456
});
4557

46-
/// The index of the currently selected item in the bottom navigation bar.
47-
final int selectedBottomNavigationIndex;
58+
/// The current status of the application.
59+
final AppLifeCycleStatus status;
4860

49-
/// The overall theme mode (light, dark, system).
50-
final ThemeMode themeMode;
61+
/// The currently authenticated or anonymous user.
62+
final User? user;
5163

52-
/// The text scale factor for the app's UI.
53-
final AppTextScaleFactor appTextScaleFactor;
64+
/// The user's application settings, including display preferences.
65+
final UserAppSettings settings;
5466

55-
/// The active color scheme defined by FlexColorScheme.
67+
/// The remote configuration fetched from the backend.
68+
final RemoteConfig? remoteConfig;
69+
70+
/// The current theme mode (light, dark, or system).
71+
final ThemeMode themeMode;
72+
73+
/// The current FlexColorScheme scheme for accent colors.
5674
final FlexScheme flexScheme;
5775

58-
/// The active font family name (e.g., from Google Fonts).
59-
/// Null uses the default font family defined in the FlexColorScheme theme.
76+
/// The currently selected font family.
6077
final String? fontFamily;
6178

62-
/// The current authentication status of the application.
63-
final AppStatus status;
64-
65-
/// The current user details. Null if unauthenticated.
66-
final User? user;
79+
/// The current text scale factor.
80+
final AppTextScaleFactor appTextScaleFactor;
6781

68-
/// User-specific application settings.
69-
final UserAppSettings settings;
82+
/// The currently selected index for bottom navigation.
83+
final int selectedBottomNavigationIndex;
7084

71-
/// The current application locale.
72-
final Locale locale;
85+
/// The current application environment.
86+
final local_config.AppEnvironment environment;
7387

74-
/// The global application configuration (remote config).
75-
final RemoteConfig? remoteConfig;
88+
/// The currently selected locale for localization.
89+
final Locale? locale;
7690

77-
/// The current application environment (e.g., production, development, demo).
78-
final local_config.AppEnvironment? environment;
91+
@override
92+
List<Object?> get props => [
93+
status,
94+
user,
95+
settings,
96+
remoteConfig,
97+
themeMode,
98+
flexScheme,
99+
fontFamily,
100+
appTextScaleFactor,
101+
selectedBottomNavigationIndex,
102+
environment,
103+
locale,
104+
];
79105

80-
/// Creates a copy of the current state with updated values.
106+
/// Creates a copy of this [AppState] with the given fields replaced with
107+
/// the new values.
81108
AppState copyWith({
82-
int? selectedBottomNavigationIndex,
109+
AppLifeCycleStatus? status,
110+
User? user,
111+
UserAppSettings? settings,
112+
RemoteConfig? remoteConfig,
113+
bool clearAppConfig = false,
83114
ThemeMode? themeMode,
84115
FlexScheme? flexScheme,
85116
String? fontFamily,
86117
AppTextScaleFactor? appTextScaleFactor,
87-
AppStatus? status, // Changed from AppStatus
88-
User? user,
89-
UserAppSettings? settings,
90-
Locale? locale,
91-
RemoteConfig? remoteConfig,
118+
int? selectedBottomNavigationIndex,
92119
local_config.AppEnvironment? environment,
93-
bool clearFontFamily = false,
94-
bool clearAppConfig = false,
95-
bool clearEnvironment = false,
120+
Locale? locale,
96121
}) {
97122
return AppState(
98-
selectedBottomNavigationIndex:
99-
selectedBottomNavigationIndex ?? this.selectedBottomNavigationIndex,
100-
themeMode: themeMode ?? this.themeMode,
101-
flexScheme: flexScheme ?? this.flexScheme,
102-
fontFamily: clearFontFamily ? null : fontFamily ?? this.fontFamily,
103-
appTextScaleFactor: appTextScaleFactor ?? this.appTextScaleFactor,
104123
status: status ?? this.status,
105124
user: user ?? this.user,
106125
settings: settings ?? this.settings,
107-
locale: locale ?? this.locale,
108126
remoteConfig: clearAppConfig ? null : remoteConfig ?? this.remoteConfig,
109-
environment: clearEnvironment ? null : environment ?? this.environment,
127+
themeMode: themeMode ?? this.themeMode,
128+
flexScheme: flexScheme ?? this.flexScheme,
129+
fontFamily: fontFamily ?? this.fontFamily,
130+
appTextScaleFactor: appTextScaleFactor ?? this.appTextScaleFactor,
131+
selectedBottomNavigationIndex:
132+
selectedBottomNavigationIndex ?? this.selectedBottomNavigationIndex,
133+
environment: environment ?? this.environment,
134+
locale: locale ?? this.locale,
110135
);
111136
}
112-
113-
@override
114-
List<Object?> get props => [
115-
selectedBottomNavigationIndex,
116-
themeMode,
117-
flexScheme,
118-
fontFamily,
119-
appTextScaleFactor,
120-
status,
121-
user,
122-
settings,
123-
locale,
124-
remoteConfig,
125-
environment,
126-
];
127137
}

lib/app/view/app.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -188,15 +188,15 @@ class _AppView extends StatefulWidget {
188188

189189
class _AppViewState extends State<_AppView> {
190190
late final GoRouter _router;
191-
late final ValueNotifier<AppStatus> _statusNotifier;
191+
late final ValueNotifier<AppLifeCycleStatus> _statusNotifier;
192192
AppStatusService? _appStatusService;
193193

194194
@override
195195
void initState() {
196196
super.initState();
197197
final appBloc = context.read<AppBloc>();
198198
// Initialize the notifier with the BLoC's current state
199-
_statusNotifier = ValueNotifier<AppStatus>(appBloc.state.status);
199+
_statusNotifier = ValueNotifier<AppLifeCycleStatus>(appBloc.state.status);
200200

201201
// Instantiate and initialize the AppStatusService.
202202
// This service will automatically trigger checks when the app is resumed
@@ -259,7 +259,7 @@ class _AppViewState extends State<_AppView> {
259259
// By returning a dedicated widget here, we ensure these pages are
260260
// full-screen and exist outside the main app's navigation shell.
261261

262-
if (state.status == AppStatus.underMaintenance) {
262+
if (state.status == AppLifeCycleStatus.underMaintenance) {
263263
// The app is in maintenance mode. Show the MaintenancePage.
264264
//
265265
// WHY A SEPARATE MATERIALAPP?
@@ -299,7 +299,7 @@ class _AppViewState extends State<_AppView> {
299299
);
300300
}
301301

302-
if (state.status == AppStatus.updateRequired) {
302+
if (state.status == AppLifeCycleStatus.updateRequired) {
303303
// A mandatory update is required. Show the UpdateRequiredPage.
304304
return MaterialApp(
305305
debugShowCheckedModeBanner: false,
@@ -326,8 +326,8 @@ class _AppViewState extends State<_AppView> {
326326
);
327327
}
328328

329-
if (state.status == AppStatus.configFetching ||
330-
state.status == AppStatus.configFetchFailed) {
329+
if (state.status == AppLifeCycleStatus.configFetching ||
330+
state.status == AppLifeCycleStatus.configFetchFailed) {
331331
// The app is in the process of fetching its initial remote
332332
// configuration or has failed to do so. The StatusPage handles
333333
// both the loading indicator and the retry mechanism.

lib/router/router.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ import 'package:go_router/go_router.dart';
5656
/// Requires an [authStatusNotifier] to trigger route re-evaluation when
5757
/// authentication state changes.
5858
GoRouter createRouter({
59-
required ValueNotifier<AppStatus> authStatusNotifier,
59+
required ValueNotifier<AppLifeCycleStatus> authStatusNotifier,
6060
required AuthRepository authenticationRepository,
6161
required DataRepository<Headline> headlinesRepository,
6262
required DataRepository<Topic> topicsRepository,
@@ -119,7 +119,7 @@ GoRouter createRouter({
119119
// --- Case 1: Unauthenticated User ---
120120
// If the user is unauthenticated, they should be on an auth path.
121121
// If they are trying to access any other part of the app, redirect them.
122-
if (appStatus == AppStatus.unauthenticated) {
122+
if (appStatus == AppLifeCycleStatus.unauthenticated) {
123123
print(' Redirect: User is unauthenticated.');
124124
// If they are already on an auth path, allow it. Otherwise, redirect.
125125
return isGoingToAuth ? null : authenticationPath;
@@ -129,14 +129,14 @@ GoRouter createRouter({
129129
// If a user is anonymous or authenticated, they should not be able to
130130
// access the main authentication flows, with an exception for account
131131
// linking for anonymous users.
132-
if (appStatus == AppStatus.anonymous ||
133-
appStatus == AppStatus.authenticated) {
132+
if (appStatus == AppLifeCycleStatus.anonymous ||
133+
appStatus == AppLifeCycleStatus.authenticated) {
134134
print(' Redirect: User is $appStatus.');
135135

136136
// If the user is trying to access an authentication path:
137137
if (isGoingToAuth) {
138138
// A fully authenticated user should never see auth pages.
139-
if (appStatus == AppStatus.authenticated) {
139+
if (appStatus == AppLifeCycleStatus.authenticated) {
140140
print(
141141
' Action: Authenticated user on auth path. Redirecting to feed.',
142142
);

lib/status/view/status_page.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class StatusPage extends StatelessWidget {
2626
builder: (context, state) {
2727
final l10n = AppLocalizationsX(context).l10n;
2828

29-
if (state.status == AppStatus.configFetching) {
29+
if (state.status == AppLifeCycleStatus.configFetching) {
3030
// While fetching configuration, display a clear loading indicator.
3131
// This uses a shared widget from the UI kit for consistency.
3232
return LoadingStateWidget(

0 commit comments

Comments
 (0)