Skip to content

Commit 6427e91

Browse files
authored
Merge pull request #14 from flutter-news-app-full-source-code/sync-docs-with-mobile-client-app-status-feature
Sync docs with mobile client app status feature
2 parents b55752d + 88c54bf commit 6427e91

File tree

3 files changed

+132
-3
lines changed

3 files changed

+132
-3
lines changed

astro.config.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,13 +157,15 @@ export default defineConfig({
157157
label: 'Features',
158158
collapsed: true,
159159
items: [
160+
{ label: 'Overview', link: '/mobile-client/features/' },
160161
{ label: 'Account', link: '/mobile-client/features/account' },
161162
{ label: 'Authentication', link: '/mobile-client/features/authentication' },
162163
{ label: 'Entity Details', link: '/mobile-client/features/entity-details' },
163164
{ label: 'Headline Details', link: '/mobile-client/features/headline-details' },
164165
{ label: 'Headlines Feed', link: '/mobile-client/features/headlines-feed' },
165166
{ label: 'Search', link: '/mobile-client/features/search' },
166167
{ label: 'Settings', link: '/mobile-client/features/settings' },
168+
{ label: 'Status Pages', link: '/mobile-client/features/status-pages' },
167169
],
168170
},
169171
{ label: 'Deployment', link: '/mobile-client/deployment' },

src/content/docs/mobile-client/architecture/routing.mdx

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,109 @@
11
---
22
title: Routing & Navigation
3-
description: Learn about the navigation structure and routing implementation in the mobile client.
3+
description: Learn about the startup flow and routing architecture that powers the mobile client.
44
---
5-
import { Card, CardGrid } from '@astrojs/starlight/components';
5+
import { Card, CardGrid, Aside } from '@astrojs/starlight/components';
66

7-
Navigation in the mobile client is managed by the powerful `go_router` package. This provides a declarative, URL-based routing system that is robust, type-safe, and easy to maintain. All routing configuration is centralized within the `lib/router/` directory.
7+
The mobile client employs a sophisticated, multi-path startup sequence to handle authentication and remote configuration checks gracefully. This ensures the app is always in a valid state before rendering the main UI.
88

9+
## The Application Startup Flow
10+
11+
The startup logic is orchestrated by the `AppBloc` and the root `_AppView` widget. The path the user experiences depends on their initial authentication status.
12+
13+
<Aside>
14+
A key architectural decision is that the **Remote Configuration API requires authentication**. This means the app must first establish a user session (even an anonymous one) before it can check for maintenance mode or required updates.
15+
</Aside>
16+
17+
### Path 1: New or Logged-Out User
18+
19+
This is the flow for a user with no existing session.
20+
21+
1. **Auth Check**: On startup, the `AppBloc` checks for a user. None is found.
22+
2. **State Transition**: The `AppBloc` immediately emits the `AppStatus.unauthenticated` state.
23+
3. **Router Activation**: The `_AppView` widget sees a "running" state (`unauthenticated`) and builds the main `MaterialApp.router`, activating `GoRouter`.
24+
4. **Redirection**: `GoRouter`'s `redirect` logic intercepts the navigation, sees the `unauthenticated` status, and immediately redirects the user to the `/authentication` page.
25+
26+
In this scenario, the user is taken directly to the sign-in screen without any intermediate loading pages.
27+
28+
### Path 2: Existing User (Authenticated or Anonymous)
29+
30+
This flow handles users who already have an active session.
31+
32+
1. **Auth Check**: On startup, the `AppBloc` finds an existing user session.
33+
2. **Initial State**: The `AppBloc` emits the corresponding status (`authenticated` or `anonymous`) and immediately dispatches an `AppConfigFetchRequested` event.
34+
3. **Pre-Router Status Pages**: The `_onAppConfigFetchRequested` handler sets the state to `AppStatus.configFetching`. The `_AppView` widget detects this critical status and displays a full-screen `StatusPage` *before* building the main router. This pre-flight check handles several possibilities:
35+
- **Loading**: A `StatusPage` with a loading indicator is shown.
36+
- **Failure**: If the config fetch fails, the `StatusPage` shows a retry button.
37+
- **Maintenance/Update**: If the config dictates, a `MaintenancePage` or `UpdateRequiredPage` is shown.
38+
4. **Router Activation**: Only after the remote config is successfully fetched and no critical status is found does the `_AppView` build the `MaterialApp.router`.
39+
5. **Redirection**: `GoRouter`'s `redirect` logic sees the `authenticated` or `anonymous` status and navigates the user to the main `/feed`.
40+
41+
This two-path system correctly prioritizes authentication and then uses that session to securely fetch critical app configuration.
42+
43+
<Aside title="Automatic Status Re-checks" icon="sync">
44+
The application includes an `AppStatusService` that automatically re-fetches the remote configuration in the background. This service triggers a check when the app is resumed from the background or at a periodic interval (e.g., every 15 minutes).
45+
46+
These background fetches are "silent" (`isBackgroundCheck: true`), meaning they do not show a loading screen. If the new configuration indicates a critical status (like maintenance mode), the app will immediately transition to the appropriate status page. This ensures the app can react to server-side changes in near real-time without disrupting the user unless absolutely necessary.
47+
</Aside>
48+
49+
## GoRouter Implementation Details
50+
51+
Once the startup flow is complete and the router is active, `go_router` manages all in-app navigation.
52+
53+
### Core Concepts
54+
55+
- **`GoRouter`**: The main router instance that controls the application's navigation stack. It is configured with a list of routes, redirect logic, and a refresh listener.
56+
57+
- **`Routes` Class**: A class located in `lib/router/routes.dart` that defines all route paths and names as `static const String` constants. Using named routes (e.g., `context.goNamed(Routes.settingsName)`) instead of raw path strings is a best practice that prevents typos and makes the code more maintainable.
58+
59+
- **`StatefulShellRoute`**: This is a key component from `go_router` used to implement persistent UI elements, such as the main bottom navigation bar. It wraps the main sections of the app (e.g., Headlines Feed, Search, Account) and manages a separate navigation stack for each section, preserving the navigation state as the user switches between tabs.
60+
61+
### Key Implementations
62+
63+
<CardGrid>
64+
<Card title="Centralized Configuration" icon="file-tree">
65+
All route definitions are located in `lib/router/router.dart`. This file contains the `GoRouter` setup, including the tree of `GoRoute` and `StatefulShellRoute` widgets that define the entire navigation map of the application.
66+
</Card>
67+
<Card title="Authentication-Aware Redirects" icon="shield-check">
68+
The router is configured with a `redirect` logic that depends on the application's authentication status, which is provided by the `AppBloc`. This ensures that unauthenticated users are automatically redirected to the sign-in page, while authenticated users are directed to the main app content, creating a secure and seamless user experience.
69+
</Card>
70+
<Card title="Type-Safe Navigation" icon="shield">
71+
By using named routes defined in the `Routes` class, navigation calls throughout the app are type-safe. This approach reduces runtime errors and makes it easy to refactor or update routes, as any changes only need to be made in one central location.
72+
</Card>
73+
<Card title="Passing Arguments" icon="box">
74+
The router is used to pass complex data between pages. For example, when navigating to a details page, the full `Headline` object is passed via the `extra` parameter of the navigation call. This is more efficient than passing an ID and re-fetching data that is already available.
75+
</Card>
76+
</CardGrid>
77+
78+
### Route Structure
79+
80+
The main application routes are structured using a `StatefulShellRoute`, which provides the bottom navigation bar. Top-level routes are used for pages that should appear over the main shell, such as authentication or detailed content views.
81+
82+
```tree title="Main Route Tree"
83+
/
84+
├─ /feed
85+
│ ├─ article/:id
86+
│ ├─ notifications
87+
│ └─ filter
88+
│ ├─ topics
89+
│ └─ sources
90+
├─ /search
91+
│ └─ article/:id
92+
└─ /account
93+
├─ settings
94+
│ ├─ appearance
95+
│ │ ├─ theme
96+
│ │ └─ font
97+
│ ├─ feed
98+
│ └─ language
99+
├─ manage-followed-items
100+
│ ├─ topics
101+
│ │ └─ add-topic
102+
│ └─ sources
103+
│ └─ add-source
104+
└─ saved-headlines
105+
└─ article/:id
106+
```
9107
## Core Concepts
10108

11109
- **`GoRouter`**: The main router instance that controls the application's navigation stack. It is configured with a list of routes, redirect logic, and a refresh listener.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
title: 'Feature: Status Pages'
3+
description: Learn about the critical, app-wide status pages for maintenance and required updates.
4+
---
5+
import { Card, CardGrid, Aside } from '@astrojs/starlight/components';
6+
7+
The mobile client includes a set of full-screen status pages designed to handle critical, app-wide states. These pages are a key part of the [two-tiered routing architecture](/docs/mobile-client/architecture/routing) and are displayed *before* the main application UI and router are ever built.
8+
9+
This mechanism is triggered by the `RemoteConfig` object fetched from the backend upon application startup. It allows administrators to communicate important information to all users or enforce mandatory updates.
10+
11+
<Aside>
12+
The logic for displaying these pages resides in the `_AppView` widget (`lib/app/view/app.dart`), which listens to the `AppStatus` from the `AppBloc`.
13+
</Aside>
14+
15+
## The Status Pages
16+
17+
<CardGrid>
18+
<Card title="Maintenance Page" icon="construction">
19+
When the `isUnderMaintenance` flag in the `RemoteConfig` is set to `true`, the application will display the `MaintenancePage`. This page informs the user that the app is temporarily unavailable and prevents them from proceeding further. It's a crucial tool for performing server-side updates without disrupting users with a broken app.
20+
</Card>
21+
<Card title="Update Required Page" icon="system-update">
22+
If the `isLatestVersionOnly` flag is `true` in the `RemoteConfig`, the `UpdateRequiredPage` is shown. This page instructs the user that they must update to the latest version of the app to continue. It includes a button that links directly to the appropriate app store (Apple App Store or Google Play Store), using the URL also provided in the `RemoteConfig`.
23+
</Card>
24+
<Card title="Initial Status Page" icon="cloud-download">
25+
This is the very first UI the user sees when a remote configuration check is required. The `StatusPage` handles two states:
26+
- **Loading**: Displays a loading indicator while the app is fetching the remote config (`AppStatus.configFetching`).
27+
- **Failure**: If the fetch fails, it shows an error message and a "Retry" button, allowing the user to attempt the connection again (`AppStatus.configFetchFailed`).
28+
</Card>
29+
</CardGrid>

0 commit comments

Comments
 (0)