Skip to main content

State Management

Provider Pattern

All ViewModels extend ChangeNotifier. They are registered as Factory or LazySingleton in service_locator.dart and consumed via context.watch<T>() or context.read<T>().

ViewModel Registry

// service_locator.dart
getIt.registerFactory<AuthViewModel>(() => AuthViewModel(getIt()));
getIt.registerFactory<HomeViewModel>(() => HomeViewModel(getIt(), getIt()));
getIt.registerFactoryParam<TripDetailViewModel, String, void>(
(tripId, _) => TripDetailViewModel(getIt(), tripId),
);
getIt.registerFactoryParam<StudentsViewModel, String, void>(
(tripId, _) => StudentsViewModel(getIt(), tripId),
);
getIt.registerFactory<IncidentsViewModel>(() => IncidentsViewModel(getIt()));
getIt.registerFactory<ProfileViewModel>(() => ProfileViewModel(getIt()));

HomeViewModel

Manages assigned bus, day trips, current location, and trip state.

class HomeViewModel extends ChangeNotifier {
final HomeRepo _homeRepo;
final LocationService _locationService;

List<DayTripsModel> _dayTrips = [];
BusModel? _assignedBus;
LatLng? _currentLocation;
bool _isLoading = false;

List<DayTripsModel> get dayTrips => _dayTrips;
BusModel? get assignedBus => _assignedBus;
LatLng? get currentLocation => _currentLocation;

Future<void> init() async {
_isLoading = true;
notifyListeners();

await Future.wait([
_loadBusAssignment(),
_loadTrips(),
_startLocationUpdates(),
]);

_isLoading = false;
notifyListeners();
}

Future<void> _loadBusAssignment() async {
final result = await _homeRepo.getAssignedBus();
result.fold(
(failure) => null,
(bus) => _assignedBus = bus,
);
}

Future<void> _loadTrips() async {
final result = await _homeRepo.getTrips();
result.fold(
(failure) => null,
(trips) => _dayTrips = trips,
);
}

Future<void> _startLocationUpdates() async {
_locationService.locationStream.listen((position) {
_currentLocation = LatLng(position.latitude, position.longitude);
notifyListeners();
});
}
}

LocationService

Uses geolocator for GPS and buffers updates for batch sending:

class LocationService {
Stream<Position> get locationStream {
return Geolocator.getPositionStream(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 10, // meters
),
);
}

Future<Position?> getCurrentPosition() {
return Geolocator.getCurrentPosition();
}
}