Public Access
258 lines
7.9 KiB
Dart
258 lines
7.9 KiB
Dart
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;
|
||
}
|
||
}
|