part of 'data_service.dart'; extension DataServiceTrips on DataService { Future fetchTripDetails() async { _isTripDetailsLoading = true; try { final json = await api.get('/trips/info'); final tripDetails = _parseTripInfoList(json); _tripDetails = [...tripDetails]..sort(TripDetail.compareByDateDesc); _tripList = tripDetails .map( (detail) => TripSummary( tripId: detail.id, tripName: detail.name, tripMileage: detail.mileage, legCount: detail.legCount, locoStats: detail.locoStats, startDate: detail.startDate, endDate: detail.endDate, ), ) .toList() ..sort(TripSummary.compareByDateDesc); } catch (e) { debugPrint('Failed to fetch trip_map: $e'); _tripDetails = []; _tripList = []; } finally { _isTripDetailsLoading = false; _notifyAsync(); } } Future> fetchTripLocoStats(int tripId) async { try { final json = await api.get('/trips/stats/$tripId'); return TripLocoStat.listFromJson(json); } catch (e) { debugPrint('Failed to fetch trip loco stats: $e'); return []; } } Future fetchTrips() async { try { final json = await api.get('/trips/info'); final raw = _extractTrips(json); if (raw != null) { final tripMap = raw .whereType>() .map((e) => TripSummary.fromJson(e)) .toList(); _tripList = [...tripMap]..sort(TripSummary.compareByDateDesc); } else { debugPrint('Unexpected trip list response: $json'); _tripList = []; } } catch (e) { debugPrint('Failed to fetch trip list: $e'); _tripList = []; } finally { _notifyAsync(); } } Future fetchTripOptions() async { try { final json = await api.get('/trips'); Iterable? raw; if (json is List) { raw = json; } else if (json is Map) { for (final key in ['trips', 'trip_data', 'data']) { final value = json[key]; if (value is List) { raw = value; break; } } } if (raw != null) { final tripMap = raw .whereType>() .map((e) => TripSummary.fromJson(e)) .toList(); _tripList = [...tripMap]..sort(TripSummary.compareByDateDesc); } else { debugPrint('Unexpected trip list response: $json'); _tripList = []; } } catch (e) { debugPrint('Failed to fetch trip list: $e'); _tripList = []; } finally { _notifyAsync(); } } void upsertTripSummary(TripSummary trip) { final existingIndex = _tripList.indexWhere( (element) => element.tripId == trip.tripId, ); if (existingIndex >= 0) { _tripList[existingIndex] = trip; } else { _tripList = [trip, ..._tripList]; } _tripList.sort(TripSummary.compareByDateDesc); _notifyAsync(); } Iterable? _extractTrips(dynamic json) { if (json is List) return json; if (json is Map) { for (final key in ['trips', 'trip_data', 'data', 'trip_info']) { final value = json[key]; if (value is List) return value; } } return null; } List _parseTripInfoList(dynamic json) { final raw = _extractTrips(json); if (raw == null) return const []; return raw .whereType>() .map((e) => TripDetail.fromJson(e)) .toList(); } }