// 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 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(); // Tracker module is not supported on desktop if (defaultTargetPlatform != TargetPlatform.windows && defaultTargetPlatform != TargetPlatform.linux && defaultTargetPlatform != TargetPlatform.macOS) { // Tracker module is not supported on web Permission.location.request().then((value) { if (value.isGranted) { trackerModule = TrackerModule(); } }); } print("Initialised LiveInformation"); } // 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 routeVariantDelegate = EventDelegate(); // Internal methods Future 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 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); } // Public methods BusRouteVariant? getRouteVariant() { return _currentRouteVariant; } Future 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 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 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;