Application Architecture
The app follows a layered architecture with clear separation of concerns:Complete Data Flow Example
Let’s trace a route search from user input to UI display.1. User Input
User fills out the search form inHomeScreen:
lib/screens/home/home_screen.dart:165-230
2. Service Call
The screen callsRouteService to fetch routes:
lib/screens/home/home_screen.dart:55-83
3. API Request
RouteService uses ApiService to make HTTP request:
lib/services/route_service.dart:13-27
4. HTTP Client
ApiService executes the HTTP request:
lib/services/api_service.dart:31-55
5. Backend API
Request is sent to backend:6. Response Processing
Backend responds with JSON:7. Model Parsing
JSON is parsed into Dart models:lib/models/route_option.dart:24-35
8. State Update
Screen updates state with parsed data:9. UI Rendering
Widget tree rebuilds with new data:lib/screens/home/home_screen.dart:246-256
10. Display Component
RouteCard displays the route:
lib/screens/home/home_screen.dart:251-254
Request/Response Flow Diagram
Authentication Flow
Authenticated requests include additional steps.1. User Login
2. Token Storage
lib/services/auth_service.dart:60-62
3. Token Retrieval
lib/services/api_service.dart:10-13
4. Authorization Header
lib/services/api_service.dart:21-23
5. Authenticated Request
Error Handling Flow
Errors propagate up the call stack.1. Network Error
lib/services/api_service.dart:52-54
2. HTTP Error
lib/services/api_service.dart:46-50
3. Service Catches Error
Service passes error to caller (or handles it).4. UI Handles Error
lib/screens/home/home_screen.dart:76-82
State Management Flow (with Provider)
Using Provider centralizes state management.1. User Action
2. Provider Updates State
3. UI Reacts
Real-time Data Flow
For features like bus schedules that update frequently:1. Initial Load
2. Pull to Refresh
lib/screens/buses/upcoming_buses_screen.dart:196-198
3. Periodic Updates (Optional)
Local Data Persistence
Some data is cached locally.1. Save to Storage
lib/services/auth_service.dart:60-62
2. Load from Storage
lib/services/auth_service.dart:19-27
3. Clear Storage
lib/services/auth_service.dart:109-111
Best Practices
1. Separation of Concerns
- UI: Only rendering and user interactions
- Services: Business logic and API calls
- Models: Data structures
- Providers: State management
2. Error Propagation
- Services throw exceptions
- UI catches and displays errors
- Provide user-friendly error messages
3. Loading States
- Always show loading indicators
- Disable buttons during async operations
- Prevent duplicate requests
4. Async/Await
- Use
async/awaitfor cleaner code - Handle errors with try/catch
- Always check
mountedbefore setState
5. State Updates
- Call
setState()after state changes - Call
notifyListeners()in providers - Avoid unnecessary rebuilds