Initial commit: SIBU 2.0 MISSION
This commit is contained in:
207
old/lib/services/app_state_service.dart
Normal file
207
old/lib/services/app_state_service.dart
Normal file
@ -0,0 +1,207 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
|
||||
import '../models/route_model.dart';
|
||||
import './transportation_service.dart';
|
||||
|
||||
/// Global app state service to manage selected route across the entire app
|
||||
class AppStateService extends ChangeNotifier {
|
||||
static final AppStateService _instance = AppStateService._internal();
|
||||
factory AppStateService() => _instance;
|
||||
AppStateService._internal();
|
||||
|
||||
final TransportationService _transportationService = TransportationService();
|
||||
|
||||
// Global state
|
||||
String? _selectedRouteId;
|
||||
String? _selectedRouteName;
|
||||
List<RouteModel> _allRoutes = [];
|
||||
bool _isLoadingRoutes = false;
|
||||
String? _error;
|
||||
|
||||
// Getters
|
||||
String? get selectedRouteId => _selectedRouteId;
|
||||
String? get selectedRouteName => _selectedRouteName;
|
||||
List<RouteModel> get allRoutes => List.unmodifiable(_allRoutes);
|
||||
bool get isLoadingRoutes => _isLoadingRoutes;
|
||||
String? get error => _error;
|
||||
bool get hasSelectedRoute =>
|
||||
_selectedRouteId != null && _selectedRouteName != null;
|
||||
|
||||
/// Initialize app state - call this on app start
|
||||
Future<void> initialize() async {
|
||||
await loadRoutes();
|
||||
}
|
||||
|
||||
/// Load all routes from Supabase
|
||||
Future<void> loadRoutes() async {
|
||||
if (_isLoadingRoutes) return;
|
||||
|
||||
_isLoadingRoutes = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
final result = await _transportationService.getRoutesWithCount();
|
||||
final routes = result['data'] as List<RouteModel>;
|
||||
final count = result['count'] as int;
|
||||
final error = result['error'] as String?;
|
||||
|
||||
if (error != null) {
|
||||
print('Error loading routes: $error');
|
||||
// Handle error but continue with empty list
|
||||
_allRoutes = [];
|
||||
} else {
|
||||
_allRoutes = routes;
|
||||
|
||||
// Auto-select first route if none selected and routes available
|
||||
if (routes.isNotEmpty && _selectedRouteId == null) {
|
||||
await selectRoute(routes.first.id);
|
||||
}
|
||||
}
|
||||
|
||||
_isLoadingRoutes = false;
|
||||
notifyListeners();
|
||||
|
||||
// Show toast if no routes found as specified in requirements
|
||||
if (_allRoutes.isEmpty) {
|
||||
_showNoRoutesToast();
|
||||
}
|
||||
} catch (e) {
|
||||
print('Exception loading routes: $e');
|
||||
_allRoutes = [];
|
||||
_isLoadingRoutes = false;
|
||||
notifyListeners();
|
||||
|
||||
// Show error toast for exceptions
|
||||
Fluttertoast.showToast(
|
||||
msg: "Error loading routes: ${e.toString()}",
|
||||
toastLength: Toast.LENGTH_LONG,
|
||||
gravity: ToastGravity.CENTER,
|
||||
backgroundColor: Colors.red,
|
||||
textColor: Colors.white,
|
||||
fontSize: 16.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _showNoRoutesToast() {
|
||||
Fluttertoast.showToast(
|
||||
msg: "No routes found",
|
||||
toastLength: Toast.LENGTH_LONG,
|
||||
gravity: ToastGravity.CENTER,
|
||||
backgroundColor: Colors.orange,
|
||||
textColor: Colors.white,
|
||||
fontSize: 16.0,
|
||||
);
|
||||
}
|
||||
|
||||
/// Select a route and update global state
|
||||
Future<void> selectRoute(String routeId) async {
|
||||
if (routeId == _selectedRouteId) return;
|
||||
|
||||
try {
|
||||
// Find the route in our cached routes
|
||||
final route = _allRoutes.firstWhere(
|
||||
(r) => r.id == routeId,
|
||||
orElse: () => throw Exception('Route not found: $routeId'),
|
||||
);
|
||||
|
||||
_selectedRouteId = routeId;
|
||||
_selectedRouteName = route.displayName;
|
||||
_error = null;
|
||||
|
||||
debugPrint('✅ Route selected: $routeId - $_selectedRouteName');
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
_error = 'Error selecting route: $e';
|
||||
debugPrint('❌ Error selecting route: $e');
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear selected route
|
||||
void clearSelectedRoute() {
|
||||
_selectedRouteId = null;
|
||||
_selectedRouteName = null;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Get selected route model
|
||||
RouteModel? getSelectedRoute() {
|
||||
if (_selectedRouteId == null) return null;
|
||||
try {
|
||||
return _allRoutes.firstWhere((r) => r.id == _selectedRouteId!);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Private method to select first available route with stops
|
||||
Future<void> _selectFirstAvailableRoute() async {
|
||||
for (final route in _allRoutes) {
|
||||
try {
|
||||
final stops =
|
||||
await _transportationService.getRouteStopsOrderedBySeq(route.id);
|
||||
if (stops.isNotEmpty) {
|
||||
_selectedRouteId = route.id;
|
||||
_selectedRouteName = route.displayName;
|
||||
debugPrint(
|
||||
'✅ Auto-selected route: ${route.id} - ${route.displayName}');
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('⚠️ Error checking stops for route ${route.id}: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: select first route even if no stops
|
||||
if (_allRoutes.isNotEmpty) {
|
||||
final firstRoute = _allRoutes.first;
|
||||
_selectedRouteId = firstRoute.id;
|
||||
_selectedRouteName = firstRoute.displayName;
|
||||
debugPrint(
|
||||
'✅ Fallback: selected first route: ${firstRoute.id} - ${firstRoute.displayName}');
|
||||
}
|
||||
}
|
||||
|
||||
/// Refresh routes and maintain selection if possible
|
||||
Future<void> refreshRoutes() async {
|
||||
final previousSelectedId = _selectedRouteId;
|
||||
await loadRoutes();
|
||||
|
||||
// Try to restore previous selection
|
||||
if (previousSelectedId != null &&
|
||||
_allRoutes.any((r) => r.id == previousSelectedId)) {
|
||||
await selectRoute(previousSelectedId);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get route by ID
|
||||
RouteModel? getRouteById(String routeId) {
|
||||
try {
|
||||
return _allRoutes.firstWhere((r) => r.id == routeId);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if route exists
|
||||
bool hasRoute(String routeId) {
|
||||
return _allRoutes.any((r) => r.id == routeId);
|
||||
}
|
||||
|
||||
/// Show toast message for no routes found
|
||||
void showNoRoutesToast(BuildContext context) {
|
||||
if (_allRoutes.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('No routes found'),
|
||||
backgroundColor: Colors.orange,
|
||||
duration: Duration(seconds: 3),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user