From 1c0616fa86cef6319bfd2edb365630039b41fdc0 Mon Sep 17 00:00:00 2001 From: fbachus Date: Thu, 23 Jul 2026 21:42:13 +0200 Subject: [PATCH] feat(departures): make some adaptations to supp diff departure srces with these adaptations to the api_handler and Departure.fromJson, the fromJson-factory now works for responses from both /departureBoard and /tripDetail for /tripDetail a little json-copying is used, see ApiHandler._expandDeparturesJson --- lib/api_handler.dart | 24 ++++++++++++++++++++++-- lib/main.dart | 6 +++--- lib/transport_helper.dart | 27 +++++++++++++++++++++++---- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/lib/api_handler.dart b/lib/api_handler.dart index 0f19c6a..3642a7d 100644 --- a/lib/api_handler.dart +++ b/lib/api_handler.dart @@ -218,10 +218,30 @@ class ApiHandler { json.decode(jsonResponse.body) as Map; final DepartureList = httpPackageJson["Stops"]["Stop"] .map( - (x) => Departure.fromJson(x), + (x) => Departure.fromJson( + // needed because I'm too lazy to write a second mostly identical + // constructor and a wrapper + _expandDeparturesJson(httpPackageJson, x, ["ref", "Product"]), + ), ) .toList() .cast(); return DepartureList; } -} \ No newline at end of file + + // workaround for the fact that json from tripDetail and DepartureBoard are + // quite different from each other in their structure... but I don't wish to + // build a second constructor >:( + // so this function duplicates topLevel Maps into a lower level to be used in + // mapping functions and such + static Map _expandDeparturesJson( + Map topLevelJson, + Map subLevelJson, + List topLevelKeys, + ) { + for (final String entry in topLevelKeys) { + subLevelJson[entry] = topLevelJson[entry]; + } + return subLevelJson; + } +} diff --git a/lib/main.dart b/lib/main.dart index 9e8c1da..9f822ca 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -348,7 +348,7 @@ class _ChooseArrivalPageState extends State { Expanded( child: SizedBox( height: 400, - child: DepartureList( + child: ArrivalList( departureList: departureList, onTapped: _handleArrivalTapped, ), @@ -398,11 +398,11 @@ class ArrivalList extends StatelessWidget { children: [ for (Departure departure in departureList) ListTile( - title: Text(departure.stationId), + title: Text(departure.stationName), subtitle: Text(departure.arrivalTime.toString()), onTap: () => onTapped(departure), ), ], ); } -} \ No newline at end of file +} diff --git a/lib/transport_helper.dart b/lib/transport_helper.dart index 785d6f7..83fdc26 100644 --- a/lib/transport_helper.dart +++ b/lib/transport_helper.dart @@ -824,16 +824,32 @@ class Departure { ); } + // this function is built to construct from different json sources + // for our hafas api, that means requests to both /departureBoard and /tripDetail + // sources from departureBoard were the default, but with some adaptations, + // tripDetail is a working source too, with the following workarounds: + // + // tripDetail has stops as list in a sublevel, whereas "ref", and "Product" + // are in the top Level. + // stop/station infos on the other hand just use different keys + // Therefore this function uses some catches to serve both cases and needs to + // be served a somewhat expanded json Map, as seen in + // ApiHander._expandDeparturesJson, which copies the topLevel fields into the + // repeated "Stop" entries that this function takes as json param factory Departure.fromJson(Map json) { Vehicle vehicle = Vehicle.fromJson(json["Product"][0]); vehicle.dbInsert(); Station station = Station( - id: json["stopid"], - name: json["stop"], + id: json["stopid"] ?? json["id"], + name: json["stop"] ?? json["name"], transportLines: [], ); station.dbInsert(); + // sometimes no arrivalTime exists, e.g. on the first station in a list + // and sometimes no departureTime, as for the last station... + // we might in these cases not need to ask for them, but I like a little + // redundancy more than handling null values DateTime? arrDateTime; String? arrivalDate = json["arrDate"]; String? arrivalTime = json["arrTime"]; @@ -849,7 +865,10 @@ class Departure { } return Departure( - ref: json["JourneyDetailRef"]["ref"], + // asking for tripDetail version first because + // ["JourneyDetailRef"]["ref"] cannot be caught if ["JourneyDetailRef"] + // is non-existent + ref: json["ref"] ?? json["JourneyDetailRef"]["ref"] as String, vehicleId: vehicle.id, vehicleName: vehicle.name, stationId: station.id, @@ -979,4 +998,4 @@ enum VehicleType { subway, regionalTrain, PLACEHOLDER, -} +} \ No newline at end of file