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
This commit is contained in:
fbachus
2026-07-23 21:42:13 +02:00
parent 1780a43f30
commit 1c0616fa86
3 changed files with 48 additions and 9 deletions
+22 -2
View File
@@ -218,10 +218,30 @@ class ApiHandler {
json.decode(jsonResponse.body) as Map<String, dynamic>; json.decode(jsonResponse.body) as Map<String, dynamic>;
final DepartureList = httpPackageJson["Stops"]["Stop"] final DepartureList = httpPackageJson["Stops"]["Stop"]
.map( .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() .toList()
.cast<Departure>(); .cast<Departure>();
return DepartureList; return DepartureList;
} }
}
// 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<String, dynamic> _expandDeparturesJson(
Map<String, dynamic> topLevelJson,
Map<String, dynamic> subLevelJson,
List<String> topLevelKeys,
) {
for (final String entry in topLevelKeys) {
subLevelJson[entry] = topLevelJson[entry];
}
return subLevelJson;
}
}
+3 -3
View File
@@ -348,7 +348,7 @@ class _ChooseArrivalPageState extends State<ChooseArrivalPage> {
Expanded( Expanded(
child: SizedBox( child: SizedBox(
height: 400, height: 400,
child: DepartureList( child: ArrivalList(
departureList: departureList, departureList: departureList,
onTapped: _handleArrivalTapped, onTapped: _handleArrivalTapped,
), ),
@@ -398,11 +398,11 @@ class ArrivalList extends StatelessWidget {
children: [ children: [
for (Departure departure in departureList) for (Departure departure in departureList)
ListTile( ListTile(
title: Text(departure.stationId), title: Text(departure.stationName),
subtitle: Text(departure.arrivalTime.toString()), subtitle: Text(departure.arrivalTime.toString()),
onTap: () => onTapped(departure), onTap: () => onTapped(departure),
), ),
], ],
); );
} }
} }
+23 -4
View File
@@ -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<String, dynamic> json) { factory Departure.fromJson(Map<String, dynamic> json) {
Vehicle vehicle = Vehicle.fromJson(json["Product"][0]); Vehicle vehicle = Vehicle.fromJson(json["Product"][0]);
vehicle.dbInsert(); vehicle.dbInsert();
Station station = Station( Station station = Station(
id: json["stopid"], id: json["stopid"] ?? json["id"],
name: json["stop"], name: json["stop"] ?? json["name"],
transportLines: [], transportLines: [],
); );
station.dbInsert(); 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; DateTime? arrDateTime;
String? arrivalDate = json["arrDate"]; String? arrivalDate = json["arrDate"];
String? arrivalTime = json["arrTime"]; String? arrivalTime = json["arrTime"];
@@ -849,7 +865,10 @@ class Departure {
} }
return 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, vehicleId: vehicle.id,
vehicleName: vehicle.name, vehicleName: vehicle.name,
stationId: station.id, stationId: station.id,
@@ -979,4 +998,4 @@ enum VehicleType {
subway, subway,
regionalTrain, regionalTrain,
PLACEHOLDER, PLACEHOLDER,
} }