implemented RMV public transit module including trip search, station departures, and nearby stop lookup, added "Marianum Connect" API integration with bearer token authentication and auto-refresh logic, integrated geolocator for location-based station search, added persistent storage for favorite stations and recent trip queries, and implemented comprehensive UI for journey details, trip results, and disruption alerts

This commit is contained in:
2026-05-20 19:08:05 +02:00
parent f185b3273a
commit 067012cc84
61 changed files with 7885 additions and 1 deletions
@@ -0,0 +1,77 @@
import '../../../api/connect/rmv/rmv_models.dart';
import '../../../state/app/modules/settings/bloc/settings_cubit.dart';
import '../../../storage/rmv_settings.dart';
/// Thin wrapper around the global [SettingsCubit] that keeps the RMV
/// favorites/recents bookkeeping out of every view. All mutations go through
/// here so that the cubit's write/emit cycle and the recent-list trimming
/// stay consistent.
class RmvFavoritesController {
final SettingsCubit _settings;
RmvFavoritesController(this._settings);
RmvSettings get _rmv => _settings.val().rmvSettings;
bool isFavorite(StopLocation stop) =>
_rmv.favoriteStations.any((s) => s.id == stop.id);
void toggleFavorite(StopLocation stop) {
if (isFavorite(stop)) {
removeFavorite(stop);
} else {
addFavorite(stop);
}
}
void addFavorite(StopLocation stop) {
final mutable = _settings.val(write: true).rmvSettings;
if (mutable.favoriteStations.any((s) => s.id == stop.id)) return;
mutable.favoriteStations = [...mutable.favoriteStations, stop];
}
void removeFavorite(StopLocation stop) {
final mutable = _settings.val(write: true).rmvSettings;
mutable.favoriteStations = mutable.favoriteStations
.where((s) => s.id != stop.id)
.toList();
}
void addRecent(StopLocation stop) {
final mutable = _settings.val(write: true).rmvSettings;
final filtered =
mutable.recentStations.where((s) => s.id != stop.id).toList();
filtered.insert(0, stop);
if (filtered.length > RmvSettings.maxRecents) {
filtered.removeRange(RmvSettings.maxRecents, filtered.length);
}
mutable.recentStations = filtered;
}
void clearRecents() {
_settings.val(write: true).rmvSettings.recentStations = const [];
}
void addRecentTrip(StopLocation from, StopLocation to) {
final mutable = _settings.val(write: true).rmvSettings;
final filtered = mutable.recentTripQueries
.where((q) => q.from.id != from.id || q.to.id != to.id)
.toList();
filtered.insert(
0,
RecentTripQuery(
from: from,
to: to,
timestampMs: DateTime.now().millisecondsSinceEpoch,
),
);
if (filtered.length > RmvSettings.maxRecents) {
filtered.removeRange(RmvSettings.maxRecents, filtered.length);
}
mutable.recentTripQueries = filtered;
}
void clearRecentTrips() {
_settings.val(write: true).rmvSettings.recentTripQueries = const [];
}
}