@@ -75,182 +75,82 @@ GoRouter createRouter({
75
75
debugLogDiagnostics: true , // Enable verbose logging for debugging redirects
76
76
// --- Redirect Logic ---
77
77
redirect: (BuildContext context, GoRouterState state) {
78
- // --- Get Current State ---
79
- // Safely read the AppBloc state. refreshListenable ensures this runs
80
- // within a valid context after AppBloc state changes.
81
78
final appStatus = context.read <AppBloc >().state.status;
82
- // The matched route pattern (e.g., '/authentication/email-sign-in').
79
+ final appConfig = context. read < AppBloc >().state.appConfig; // Get appConfig
83
80
final currentLocation = state.matchedLocation;
84
- // The full URI including query parameters (e.g., '/authentication?context=linking').
85
81
final currentUri = state.uri;
86
82
87
- // --- Debug Logging ---
88
- // Log current state for easier debugging of redirect behavior.
89
83
print (
90
84
'GoRouter Redirect Check:\n '
91
85
' Current Location (Matched): $currentLocation \n '
92
86
' Current URI (Full): $currentUri \n '
93
- ' AppStatus: $appStatus ' ,
87
+ ' AppStatus: $appStatus \n '
88
+ ' AppConfig isNull: ${appConfig == null }' ,
94
89
);
95
90
96
91
// --- Define Key Paths ---
97
- // Base paths for major sections.
98
- const authenticationPath = Routes .authentication; // '/authentication'
99
- const feedPath = Routes .feed; // Updated path constant
100
- // Specific authentication sub-routes crucial for the email code verification flow.
101
- const requestCodePath =
102
- '$authenticationPath /${Routes .requestCode }' ; // '/authentication/request-code'
103
- const verifyCodePath =
104
- '$authenticationPath /${Routes .verifyCode }' ; // '/authentication/verify-code'
105
-
106
- // --- Helper Booleans ---
107
- // Check if the navigation target is within the authentication section.
92
+ const authenticationPath = Routes .authentication;
93
+ const feedPath = Routes .feed;
108
94
final isGoingToAuth = currentLocation.startsWith (authenticationPath);
109
- // Check if the navigation target is within the feed section.
110
- final isGoingToFeed = currentLocation.startsWith (
111
- feedPath,
112
- ); // Updated path constant
113
- // Check if the navigation target is the *exact* base authentication path.
114
- final isGoingToBaseAuthPath = currentLocation == authenticationPath;
115
- // Check if the 'context=linking' query parameter is present in the URI.
116
- final isLinkingContext =
117
- currentUri.queryParameters['context' ] == 'linking' ;
118
- // Removed isGoingToSplash check
119
-
120
- // --- Redirect Logic based on AppStatus ---
121
95
122
- // --- Case 0: Initial Loading State ---
123
- // While the app is initializing (status is initial), don't redirect.
124
- // Let the initial navigation attempt proceed. The refreshListenable
125
- // will trigger a redirect check again once the status is known.
126
- if (appStatus == AppStatus .initial) {
96
+ // --- Case 0: App is Initializing or Config is being fetched/failed ---
97
+ if (appStatus == AppStatus .initial ||
98
+ appStatus == AppStatus .configFetching ||
99
+ appStatus == AppStatus .configFetchFailed) {
100
+
101
+ // If AppStatus is initial and trying to go to a non-auth page (e.g. initial /feed)
102
+ // redirect to auth immediately to settle auth status first.
103
+ if (appStatus == AppStatus .initial && ! isGoingToAuth) {
104
+ print (
105
+ ' Redirect Decision: AppStatus is INITIAL and not going to auth. Redirecting to $authenticationPath to settle auth first.' ,
106
+ );
107
+ return authenticationPath;
108
+ }
109
+ // For configFetching or configFetchFailed, or initial going to auth,
110
+ // let the App widget's builder handle the UI (loading/error screen).
127
111
print (
128
- ' Redirect Decision: AppStatus is INITIAL . Allowing navigation.' ,
112
+ ' Redirect Decision: AppStatus is $ appStatus . Allowing App widget to handle display or navigation to auth .' ,
129
113
);
130
- return null ; // Do not redirect during initial phase
114
+ return null ;
131
115
}
132
116
133
- // --- Case 1: Unauthenticated User (After Initial Load) ---
134
- // If the user is unauthenticated...
117
+ // --- Case 1: Unauthenticated User (after initial phase, config not relevant yet for this decision) ---
135
118
if (appStatus == AppStatus .unauthenticated) {
136
- print (' Redirect Decision: User is UNauthenticated (post-initial).' );
137
- // If the user is NOT already going to an authentication path...
119
+ print (' Redirect Decision: User is UNauthenticated.' );
138
120
if (! isGoingToAuth) {
139
- // ...redirect them to the main authentication page to sign in or sign up.
140
- print (' Action: Redirecting to $authenticationPath ' );
121
+ print (' Action: Not going to auth. Redirecting to $authenticationPath ' );
141
122
return authenticationPath;
142
123
}
143
- // Otherwise, allow them to stay on the authentication path they are navigating to.
144
- print (' Action: Allowing navigation within authentication section.' );
145
- return null ; // Allow access
124
+ print (' Action: Already going to auth. Allowing navigation.' );
125
+ return null ;
146
126
}
147
- // --- Case 2: Anonymous User ---
148
- else if (appStatus == AppStatus .anonymous) {
149
- print (' Redirect Decision: User is ANONYMOUS.' );
150
-
151
- // Define search and account paths for clarity
152
- const searchPath = Routes .search; // '/search'
153
- const accountPath = Routes .account; // '/account'
154
127
155
- // Helper booleans for search and account sections
156
- final isGoingToSearch = currentLocation.startsWith (searchPath);
157
- final isGoingToAccount = currentLocation.startsWith (accountPath);
128
+ // --- Case 2: Anonymous or Authenticated User ---
129
+ // (Covers AppStatus.anonymous and AppStatus.authenticated)
130
+ // At this point, AppConfig should be loaded or its loading/error state is handled by App widget.
131
+ // The main concern here is preventing authenticated users from re-entering basic auth flows.
132
+ if (appStatus == AppStatus .anonymous || appStatus == AppStatus .authenticated) {
133
+ print (' Redirect Decision: User is $appStatus .' );
134
+
135
+ final isLinkingContext = currentUri.queryParameters['context' ] == 'linking' ;
158
136
159
- // **Sub-Case 2.1: Navigating to the BASE Authentication Path (`/authentication`)**
160
- if (isGoingToBaseAuthPath) {
161
- // Allow access ONLY if they are explicitly starting the linking flow
162
- // (indicated by the 'context=linking' query parameter).
163
- if (isLinkingContext) {
164
- print (
165
- ' Action: Allowing navigation to BASE auth for account linking.' ,
166
- );
167
- return null ; // Allow access
168
- } else {
169
- // Prevent anonymous users from accessing the initial sign-in screen again.
170
- // Redirect them to the main content (feed).
171
- print (
172
- ' Action: Preventing access to initial sign-in, redirecting to $feedPath ' , // Updated path constant
173
- );
174
- return feedPath; // Redirect to feed
175
- }
176
- }
177
- // **Sub-Case 2.2: Navigating to Specific Email Code Verification Sub-Routes**
178
- // Explicitly allow access to the necessary pages for the email code verification process,
179
- // even if the 'context=linking' parameter is lost during navigation between these pages.
180
- else if (currentLocation == requestCodePath ||
181
- currentLocation.startsWith (verifyCodePath)) {
182
- // Use startsWith for parameterized path
183
- print (
184
- ' Action: Allowing navigation to email code verification sub-route ($currentLocation ).' ,
185
- );
186
- return null ; // Allow access
187
- }
188
- // **Sub-Case 2.3: Navigating Within the Main App Sections (Feed, Search, Account) or Details Pages**
189
- // Allow anonymous users to access the main content sections, their sub-routes, and details pages.
190
- else if (isGoingToFeed ||
191
- isGoingToSearch ||
192
- isGoingToAccount ||
193
- currentLocation == Routes .categoryDetails ||
194
- currentLocation == Routes .sourceDetails ||
195
- currentLocation.startsWith (
196
- Routes .globalArticleDetails.split ('/:id' ).first,
197
- ) || // Allow global article details
198
- currentLocation.startsWith (
199
- '${Routes .feed }/${Routes .articleDetailsName .split ('/:id' ).first }' ,
200
- ) ||
201
- currentLocation.startsWith (
202
- '${Routes .search }/${Routes .searchArticleDetailsName .split ('/:id' ).first }' ,
203
- ) ||
204
- currentLocation.startsWith (
205
- '${Routes .account }/${Routes .accountSavedHeadlines }/${Routes .accountArticleDetailsName .split ('/:id' ).first }' ,
206
- )) {
207
- print (
208
- ' Action: Allowing navigation to main app section or details page ($currentLocation ).' ,
209
- );
210
- return null ; // Allow access
211
- }
212
- // **Sub-Case 2.4: Fallback for Unexpected Paths**
213
- // If an anonymous user tries to navigate anywhere else unexpected,
214
- // redirect them to the main content feed as a safe default.
215
- else {
216
- print (
217
- ' Action: Unexpected path ($currentLocation ), redirecting to $feedPath ' ,
218
- );
219
- return feedPath; // Redirect to feed
220
- }
221
- }
222
- // --- Case 3: Authenticated User ---
223
- else if (appStatus == AppStatus .authenticated) {
224
- print (' Redirect Decision: User is AUTHENTICATED.' );
225
- // If an authenticated user tries to access any part of the authentication flow...
226
- if (isGoingToAuth) {
227
- // ...redirect them away to the main content feed. They don't need to authenticate again.
137
+ // If an authenticated/anonymous user tries to access the BASE /authentication path
138
+ // AND it's NOT for account linking, redirect them to the feed.
139
+ if (currentLocation == authenticationPath && ! isLinkingContext) {
228
140
print (
229
- ' Action: Preventing access to authentication section, redirecting to $feedPath ' , // Updated path constant
141
+ ' Action: $ appStatus user trying to access base auth path without linking context. Redirecting to $feedPath ' ,
230
142
);
231
- return feedPath; // Redirect to feed
143
+ return feedPath;
232
144
}
233
- // Otherwise, allow authenticated users to access any other part of the app (feed, account, settings, etc.).
234
- print (
235
- ' Action: Allowing navigation to non-auth section ($currentLocation ).' ,
236
- );
237
- return null ; // Allow access
238
- }
239
- // --- Case 4: Fallback (Should not be reached with initial handling) ---
240
- // This case is less likely now with explicit initial handling.
241
- // If somehow the status is unknown after the initial phase, allow navigation.
242
- else {
243
- print (
244
- ' Redirect Decision: AppStatus is UNEXPECTED ($appStatus ). Allowing navigation (fallback).' ,
245
- );
246
- return null ; // Allow access as a safe default
145
+
146
+ // Allow access to other routes (including auth sub-routes if linking, or any other app route)
147
+ print (' Action: Allowing navigation to $currentLocation for $appStatus user.' );
148
+ return null ;
247
149
}
248
150
249
- // --- Default: No Redirect (Should not be reached if logic is exhaustive) ---
250
- // If none of the above conditions triggered an explicit redirect, allow navigation.
251
- // This line should theoretically not be reached if the logic above is exhaustive.
252
- // print(' Redirect Decision: No specific redirect condition met. Allowing navigation.');
253
- // return null; // Allow access (already covered by the final return null below)
151
+ // Fallback (should ideally not be reached if all statuses are handled)
152
+ print (' Redirect Decision: Fallback, no specific condition met for $appStatus . Allowing navigation.' );
153
+ return null ;
254
154
},
255
155
// --- Authentication Routes ---
256
156
routes: [
@@ -434,14 +334,14 @@ GoRouter createRouter({
434
334
),
435
335
BlocProvider (
436
336
create: (context) {
437
- final feedInjectorService = FeedInjectorService (); // Instantiate
337
+ final feedInjectorService =
338
+ FeedInjectorService (); // Instantiate
438
339
return HeadlinesSearchBloc (
439
340
headlinesRepository:
440
341
context.read <HtDataRepository <Headline >>(),
441
342
categoryRepository:
442
343
context.read <HtDataRepository <Category >>(),
443
- sourceRepository:
444
- context.read <HtDataRepository <Source >>(),
344
+ sourceRepository: context.read <HtDataRepository <Source >>(),
445
345
appBloc: context.read <AppBloc >(), // Provide AppBloc
446
346
feedInjectorService: feedInjectorService, // Provide Service
447
347
);
0 commit comments