Files
oeffimaster/lib/api_handler.dart
T

258 lines
7.9 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:http/http.dart' as http;
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'dart:core';
import 'dart:convert';
import 'transport_helper.dart';
import 'utilities.dart';
class ApiHandler {
// TODO: Split next line for better Error Handling
static final String baseUrl = dotenv.get("VBB_API_URL");
static final String accessID = dotenv.get("VBB_API_KEY");
//static Future<Map<String, dynamic>> findStations(String locationName) async {
static Future<List<Station>> findStations(
String locationName, {
int? maxStations = 5,
}) async {
String urlPath = '/api/fahrinfo/latest/location.name';
Uri url = Uri.https(baseUrl, urlPath, {
'accessId': accessID,
'input': locationName,
'maxNo': maxStations.toString(),
'type': 'S', // Station/Stops only
});
//print(url);
var jsonResponse = await http.get(
url,
headers: {'Accept': 'application/json'},
);
final httpPackageJson =
json.decode(jsonResponse.body) as Map<String, dynamic>;
//print(httpPackageJson["stopLocationOrCoordLocation"]);
List<Station> stationList = httpPackageJson["stopLocationOrCoordLocation"]
.map(
(x) => Station.fromJson(x["StopLocation"]),
)
.toList()
.cast<Station>();
return stationList;
}
static Future<List<Station>> nearbyStations(
String latitude,
String longitude, {
int? maxStations = 5,
}) async {
String urlPath = '/api/fahrinfo/latest/location.nearbystops';
Uri url = Uri.https(baseUrl, urlPath, {
'accessId': accessID,
'originCoordLat': latitude,
'originCoordLong': longitude,
'maxNo': maxStations.toString(),
'type': 'S', // Station/Stops only
});
var jsonResponse = await http.get(
url,
headers: {'Accept': 'application/json'},
);
final httpPackageJson =
json.decode(jsonResponse.body) as Map<String, dynamic>;
final stationList = httpPackageJson["stopLocationOrCoordLocation"]
.map(
(x) => Station.fromJson(x["StopLocation"]),
)
.toList()
.cast<Station>();
return stationList;
}
static Future<List<Departure>> departures(
String stationId, {
int? maxDepartures = -1,
DateTime? datetime,
int? duration = 0,
}) async {
String urlPath = '/api/fahrinfo/latest/departureBoard';
String stationString = stationId.replaceAll(' ', '%20'); // reform for URL
Uri url = Uri.https(baseUrl, urlPath, {
'accessId': accessID,
'id': stationString,
'date': dateOf(datetime ?? DateTime.now()),
'time': timeOf(
datetime ?? DateTime.now(),
), //time from which departures will be shown
'duration': duration.toString(), //interval time in minutes
'maxJourneys': maxDepartures.toString(),
//'type': 'S', // Station/Stops only
});
var jsonResponse = await http.get(
url,
headers: {'Accept': 'application/json'},
);
final httpPackageJson =
json.decode(jsonResponse.body) as Map<String, dynamic>;
// try {
List<Departure> departureList = httpPackageJson["Departure"]
.map(
(x) => Departure.fromJson(x),
)
.toList()
.cast<Departure>();
return departureList;
// } catch (e) {
// // TODO: logging
// // empty response
// print('Error: $e');
// // print(
// // 'Response for Station-id "$stationString" contains no field "Departure": $httpPackageJson',
// // );
// return [];
// }
}
static Future<List<Departure>> departuresAggregate(
List<String> stationList, {
int? maxDepartures = -1,
int? duration = -1,
}) async {
String urlPath = '/api/fahrinfo/latest/multiDepartureBoard';
String stationListString = stationList
.reduce((value, element) => '$value|$element')
.replaceAll(' ', '%20'); // reform for URL
Uri url = Uri.https(baseUrl, urlPath, {
'accessId': accessID,
'id': stationListString,
////'time': /current time //time from which departures will be shown
'duration': duration.toString(), //interval time in minutes
'maxJourneys': maxDepartures.toString(),
'type': 'S', // Station/Stops only
});
var jsonResponse = await http.get(
url,
headers: {'Accept': 'application/json'},
);
final httpPackageJson =
json.decode(jsonResponse.body) as Map<String, dynamic>;
List<Departure> departureList = httpPackageJson["Departure"]
.map(
(x) => Departure.fromJson(x),
)
.toList()
.cast<Departure>();
return departureList;
}
static Future<List<Segment>> trip(
String originId,
String destinationId, {
String? via,
String? viaID,
String? date,
String? time,
int? maxChange,
int? minChangeTime,
int? maxChangeTime,
bool? arrivalTime,
// int? products, // which transport modi to use - ignore for now
// String rtMode, // wherether to use real time data
// String trainFilter,
}) async {
String urlPath = '/api/fahrinfo/latest/trip';
String startId = originId.replaceAll(' ', '%20'); // reform for URL
String endId = destinationId.replaceAll(' ', '%20'); // reform for URL
Uri url = Uri.https(baseUrl, urlPath, {
'accessId': accessID,
'originId': startId,
'destId': endId,
////'time': /current time //time from which departures will be shown
'time': time.toString(), //interval time in minutes
'maxChange': maxChange.toString(),
'type': 'S', // Station/Stops only
});
var jsonResponse = await http.get(
url,
headers: {'Accept': 'application/json'},
);
final httpPackageJson =
json.decode(jsonResponse.body) as Map<String, dynamic>;
// TODO: here lurk problems - do we get a list of list of segments? can't cast it
// what do we want from this?
List<Segment> SegmentList = httpPackageJson["Trip"]
.map(
(x) => x["LegList"]["Leg"].map((y) => Segment.fromJson(y)),
)
.toList();
return SegmentList;
}
static Future<List<Departure>> tripDetail(
String id, {
String? date,
String? fromId,
int? fromIdx,
String? toId,
int? toIdx,
String? startStationId,
}) async {
String urlPath = '/api/fahrinfo/latest/journeyDetail';
Uri url = Uri.https(baseUrl, urlPath, {
'accessId': accessID,
'id': id,
'fromId': fromId,
'toId': toId,
});
var jsonResponse = await http.get(
url,
headers: {'Accept': 'application/json'},
);
final httpPackageJson =
json.decode(jsonResponse.body) as Map<String, dynamic>;
Iterable<Departure> DepartureList = httpPackageJson["Stops"]["Stop"]
.map(
(x) => Departure.fromJson(
// needed because I'm too lazy to write a second mostly identical
// constructor and a wrapper
_expandDeparturesJson(httpPackageJson, x, [
"ref",
"Product",
"Directions",
]),
),
)
.cast<Departure>();
// preferably this happens always?
if (startStationId != null) {
// show Stations after the one we are at
return DepartureList.skipWhile(
(x) => x.stationId != startStationId,
).skip(1).toList();
}
return DepartureList.toList().cast<Departure>();
}
// 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;
}
}