190 lines
4.9 KiB
Dart
190 lines
4.9 KiB
Dart
|
|
// Singleton
|
|
import 'dart:async';
|
|
import 'dart:convert';
|
|
|
|
import 'package:appwrite/appwrite.dart' as appwrite;
|
|
import 'package:appwrite/models.dart' as models;
|
|
import 'package:bus_infotainment/audio_cache.dart';
|
|
import 'package:bus_infotainment/auth/api_constants.dart';
|
|
import 'package:bus_infotainment/auth/auth_api.dart';
|
|
import 'package:bus_infotainment/backend/modules/announcement.dart';
|
|
import 'package:bus_infotainment/backend/modules/commands.dart';
|
|
import 'package:bus_infotainment/backend/modules/synced_time.dart';
|
|
import 'package:bus_infotainment/backend/modules/tracker.dart';
|
|
import 'package:bus_infotainment/tfl_datasets.dart';
|
|
import 'package:bus_infotainment/utils/audio%20wrapper.dart';
|
|
import 'package:bus_infotainment/utils/delegates.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:ntp/ntp.dart';
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
|
|
class LiveInformation {
|
|
|
|
static final LiveInformation _singleton = LiveInformation._internal();
|
|
|
|
factory LiveInformation() {
|
|
return _singleton;
|
|
}
|
|
|
|
LiveInformation._internal();
|
|
|
|
Future<void> initialize() async {
|
|
|
|
{
|
|
// By default, load the bus sequences from the assets
|
|
print("Loading bus sequences from assets");
|
|
busSequences = BusSequences.fromCSV(
|
|
await rootBundle.loadString("assets/datasets/bus-blinds.csv"),
|
|
await rootBundle.loadString("assets/datasets/bus-sequences.csv")
|
|
);
|
|
print("Loaded bus sequences from assets");
|
|
|
|
try {
|
|
|
|
http.Response response = await http.get(Uri.parse('https://tfl.gov.uk/bus-sequences.csv'));
|
|
|
|
busSequences = BusSequences.fromCSV(
|
|
await rootBundle.loadString("assets/datasets/bus-blinds.csv"),
|
|
response.body
|
|
);
|
|
|
|
print("Loaded bus sequences from TFL");
|
|
|
|
} catch (e) {
|
|
print("Failed to load bus sequences from TFL. Using local copy.");
|
|
}
|
|
|
|
String sessionID = "test";
|
|
|
|
commandModule = CommandModule(sessionID);
|
|
|
|
}
|
|
|
|
// Initialise modules
|
|
syncedTimeModule = SyncedTimeModule();
|
|
announcementModule = AnnouncementModule();
|
|
|
|
initTrackerModule();
|
|
|
|
print("Initialised LiveInformation");
|
|
}
|
|
|
|
Future<void> initTrackerModule() async {
|
|
if (await Permission.location.isGranted) {
|
|
trackerModule = TrackerModule();
|
|
}
|
|
}
|
|
|
|
// Auth
|
|
AuthAPI auth = AuthAPI();
|
|
|
|
// Modules
|
|
late CommandModule commandModule;
|
|
late BusSequences busSequences;
|
|
late AnnouncementModule announcementModule;
|
|
late SyncedTimeModule syncedTimeModule;
|
|
late TrackerModule trackerModule;
|
|
|
|
// Important variables
|
|
BusRouteVariant? _currentRouteVariant;
|
|
|
|
// Events
|
|
EventDelegate<BusRouteVariant> routeVariantDelegate = EventDelegate();
|
|
|
|
// Internal methods
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> setRouteVariant_Internal(BusRouteVariant routeVariant) async {
|
|
|
|
// Set the current route variant
|
|
_currentRouteVariant = routeVariant;
|
|
|
|
// Let everyone know that the route variant has been set/changed
|
|
routeVariantDelegate.trigger(routeVariant);
|
|
|
|
// Get all of the files that need to be cached
|
|
List<String> audioFiles = [];
|
|
|
|
for (BusRouteStop stop in routeVariant.busStops) {
|
|
audioFiles.add(stop.getAudioFileName());
|
|
}
|
|
|
|
// Cache/Load the audio files
|
|
await announcementModule
|
|
.announcementCache
|
|
.loadAnnouncementsFromBytes(await LiveInformation().announcementModule.getBundleBytes(), [
|
|
...audioFiles,
|
|
if (!routeVariant.busRoute.routeNumber.toLowerCase().startsWith("ul"))
|
|
"R_${routeVariant.busRoute.routeNumber}_001.mp3"
|
|
else
|
|
"R_RAIL_REPLACEMENT_SERVICE_001.mp3",
|
|
|
|
]
|
|
);
|
|
}
|
|
|
|
// Public methods
|
|
|
|
BusRouteVariant? getRouteVariant() {
|
|
return _currentRouteVariant;
|
|
}
|
|
|
|
Future<void> setRouteVariant(BusRouteVariant routeVariant) async {
|
|
await commandModule.executeCommand(
|
|
"setroute ${routeVariant.busRoute.routeNumber} ${routeVariant.busRoute.routeVariants.values.toList().indexOf(routeVariant)}"
|
|
);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
Everything under this will be considered legacy code
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
class AnnouncementQueueEntry {
|
|
final String displayText;
|
|
final List<AudioWrapperSource> audioSources;
|
|
bool sendToServer = true;
|
|
DateTime? scheduledTime;
|
|
DateTime? timestamp;
|
|
|
|
AnnouncementQueueEntry({required this.displayText, required this.audioSources, this.sendToServer = true, this.scheduledTime, this.timestamp});
|
|
}
|
|
|
|
class NamedAnnouncementQueueEntry extends AnnouncementQueueEntry {
|
|
final String shortName;
|
|
|
|
NamedAnnouncementQueueEntry({
|
|
required this.shortName,
|
|
required String displayText,
|
|
required List<AudioWrapperSource> audioSources,
|
|
DateTime? scheduledTime,
|
|
DateTime? timestamp,
|
|
bool sendToServer = true,
|
|
}) : super(
|
|
displayText: displayText,
|
|
audioSources: audioSources,
|
|
sendToServer: sendToServer,
|
|
scheduledTime: scheduledTime,
|
|
timestamp: timestamp,
|
|
);
|
|
}
|
|
|
|
var abs = (int value) => value < 0 ? -value : value; |