diff --git a/lib/pages/home.dart b/lib/pages/home.dart index fe1705a..70eacf0 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -18,44 +18,17 @@ class pages_Home extends StatelessWidget { - child: Column( - children: [ - - Container( - height: 2, - color: Colors.white70, - ), - - Container( - - decoration: BoxDecoration( - color: Colors.grey.shade900, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.3), - blurRadius: 2, - spreadRadius: 4 - ) - ] + child: SingleChildScrollView( + child: Column( + children: [ + + Container( + height: 2, + color: Colors.white70, ), - - margin: EdgeInsets.all(20), - - child: ibus_display(), - - ), - - Container( - height: 2, - color: Colors.white70, - ), - - Container( - - margin: EdgeInsets.all(20), - - child: Container( - + + Container( + decoration: BoxDecoration( color: Colors.grey.shade900, boxShadow: [ @@ -66,148 +39,186 @@ class pages_Home extends StatelessWidget { ) ] ), - - child: ManualAnnouncementPicker( - backgroundColor: Colors.grey.shade900, - outlineColor: Colors.white70, - announcements: [ - ...LiveInformation().manualAnnouncements - ], - ), + + margin: EdgeInsets.all(20), + + child: ibus_display(), + ), - - ), - - Container( - height: 2, - color: Colors.white70, - ), - - Container( - - margin: EdgeInsets.all(20), - - child: Container( - - decoration: BoxDecoration( + + Container( + height: 2, + color: Colors.white70, + ), + + Container( + + margin: EdgeInsets.all(20), + + child: Container( + + decoration: BoxDecoration( color: Colors.grey.shade900, boxShadow: [ BoxShadow( - color: Colors.black.withOpacity(0.3), - blurRadius: 2, - spreadRadius: 4 + color: Colors.black.withOpacity(0.3), + blurRadius: 2, + spreadRadius: 4 ) ] + ), + + child: ManualAnnouncementPicker( + backgroundColor: Colors.grey.shade900, + outlineColor: Colors.white70, + announcements: [ + ...LiveInformation().manualAnnouncements + ], + ), ), - - child: DelegateBuilder( - delegate: LiveInformation().routeVariantDelegate, - builder: (context, routeVariant) { - print("rebuilt stop announcement picker"); - return StopAnnouncementPicker( - routeVariant: routeVariant, - backgroundColor: Colors.grey.shade900, - outlineColor: Colors.white70, - ); - }, - defaultBuilder: (context) { - BusRouteVariant? routeVariant = LiveInformation().getRouteVariant(); - if (routeVariant == null) { - return Container( - color: Colors.grey.shade900, - child: Center( - child: Text( - "No route selected", - style: GoogleFonts.teko( - fontSize: 25, - color: Colors.white70 - ), - ), - ), - ); - } else { + + ), + + Container( + height: 2, + color: Colors.white70, + ), + + Container( + + margin: EdgeInsets.all(20), + + child: Container( + + decoration: BoxDecoration( + color: Colors.grey.shade900, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.3), + blurRadius: 2, + spreadRadius: 4 + ) + ] + ), + + child: DelegateBuilder( + delegate: LiveInformation().routeVariantDelegate, + builder: (context, routeVariant) { + print("rebuilt stop announcement picker"); return StopAnnouncementPicker( routeVariant: routeVariant, backgroundColor: Colors.grey.shade900, outlineColor: Colors.white70, ); - } - }, + }, + defaultBuilder: (context) { + BusRouteVariant? routeVariant = LiveInformation().getRouteVariant(); + if (routeVariant == null) { + return Container( + color: Colors.grey.shade900, + child: Center( + child: Text( + "No route selected", + style: GoogleFonts.teko( + fontSize: 25, + color: Colors.white70 + ), + ), + ), + ); + } else { + return StopAnnouncementPicker( + routeVariant: routeVariant, + backgroundColor: Colors.grey.shade900, + outlineColor: Colors.white70, + ); + } + }, + ), ), + ), - - ), - - // Container( - // - // margin: EdgeInsets.all(20), - // - // height: 300-45, - // - // child: ListView( - // - // scrollDirection: Axis.vertical, - // - // children: [ - // - // ElevatedButton( - // onPressed: () async { - // LiveInformation liveInformation = LiveInformation(); - // liveInformation.queueAnnouncement(await liveInformation.getDestinationAnnouncement(liveInformation.getRouteVariant()!, sendToServer: false)); - // }, - // child: Text("Test announcement"), - // ), - // - // ElevatedButton( - // onPressed: () { - // LiveInformation liveInformation = LiveInformation(); - // liveInformation.updateServer(); - // }, - // child: Text("Update server"), - // ), - // - // SizedBox( - // - // width: 100, - // - // child: TextField( - // onChanged: (String value) { - // LiveInformation liveInformation = LiveInformation(); - // // liveInformation.documentID = value; - // }, - // ), - // ), - // - // SizedBox( - // - // width: 200, - // - // child: TextField( - // onSubmitted: (String value) { - // LiveInformation liveInformation = LiveInformation(); - // liveInformation.queueAnnouncement(AnnouncementQueueEntry( - // displayText: value, - // audioSources: [] - // )); - // }, - // ), - // ), - // - // ElevatedButton( - // onPressed: () { - // LiveInformation liveInformation = LiveInformation(); - // liveInformation.pullServer(); - // }, - // child: Text("Pull server"), - // ), - // - // ], - // - // ), - // - // ), - - ], + + ElevatedButton( + onPressed: () async { + LiveInformation liveInformation = LiveInformation(); + liveInformation.queueAnnouncement(await liveInformation.getDestinationAnnouncement(liveInformation.getRouteVariant()!, sendToServer: true)); + }, + child: Text("Announce Destination"), + ), + + + // Container( + // + // margin: EdgeInsets.all(20), + // + // height: 300-45, + // + // child: ListView( + // + // scrollDirection: Axis.vertical, + // + // children: [ + // + // ElevatedButton( + // onPressed: () async { + // LiveInformation liveInformation = LiveInformation(); + // liveInformation.queueAnnouncement(await liveInformation.getDestinationAnnouncement(liveInformation.getRouteVariant()!, sendToServer: false)); + // }, + // child: Text("Test announcement"), + // ), + // + // ElevatedButton( + // onPressed: () { + // LiveInformation liveInformation = LiveInformation(); + // liveInformation.updateServer(); + // }, + // child: Text("Update server"), + // ), + // + // SizedBox( + // + // width: 100, + // + // child: TextField( + // onChanged: (String value) { + // LiveInformation liveInformation = LiveInformation(); + // // liveInformation.documentID = value; + // }, + // ), + // ), + // + // SizedBox( + // + // width: 200, + // + // child: TextField( + // onSubmitted: (String value) { + // LiveInformation liveInformation = LiveInformation(); + // liveInformation.queueAnnouncement(AnnouncementQueueEntry( + // displayText: value, + // audioSources: [] + // )); + // }, + // ), + // ), + // + // ElevatedButton( + // onPressed: () { + // LiveInformation liveInformation = LiveInformation(); + // liveInformation.pullServer(); + // }, + // child: Text("Pull server"), + // ), + // + // ], + // + // ), + // + // ), + + ], + ), ) ); @@ -535,10 +546,8 @@ class StopAnnouncementPicker extends ManualAnnouncementPicker { ManualAnnouncementEntry( shortName: stop.formattedStopName, informationText: stop.formattedStopName, - audioSources: [ - // AudioWrapperByteSource( - // LiveInformation().announcementCache[stop.getAudioFileName()] - // ) + audioFileNames: [ + stop.getAudioFileName() ] ) ] diff --git a/lib/singletons/live_information.dart b/lib/singletons/live_information.dart index 71b732a..ae23eaa 100644 --- a/lib/singletons/live_information.dart +++ b/lib/singletons/live_information.dart @@ -101,7 +101,6 @@ class LiveInformation { AudioWrapper audioPlayer = AudioWrapper(); AnnouncementCache announcementCache = AnnouncementCache(); List announcementQueue = []; - AnnouncementQueueEntry? lastAnnouncement; DateTime lastAnnouncementTimeStamp = DateTime.now().toUtc(); EventDelegate announcementDelegate = EventDelegate(); String _currentAnnouncement = "*** NO MESSAGE ***"; @@ -133,6 +132,7 @@ class LiveInformation { // print("Q Difference: ${milisecondDifference}"); if (milisecondDifference <= timerInterval) { // Account for the time lost by the periodic timer + announcementQueue.remove(announcement); await Future.delayed(Duration(milliseconds: timerInterval - milisecondDifference)); } else { print("Due in: ${milisecondDifference}ms"); @@ -140,8 +140,7 @@ class LiveInformation { } } } - announcementQueue.removeAt(0); - lastAnnouncement = announcement; + isPlayingAnnouncement = true; if (kIsWeb) { @@ -161,10 +160,12 @@ class LiveInformation { Duration? duration = await audioPlayer.play(source); await Future.delayed(duration!); - await Future.delayed(Duration(milliseconds: 150)); + if (announcement.audioSources.last != source) { + await Future.delayed(Duration(milliseconds: 500)); + } } - } finally { audioPlayer.stop(); + } catch (e) { } } else { @@ -173,8 +174,13 @@ class LiveInformation { } } + if (announcementQueue.contains(announcement)) { + announcementQueue.remove(announcement); + } + isPlayingAnnouncement = false; print("Popped announcement queue"); + print("Queue length after: ${announcementQueue.length}"); } } } @@ -283,6 +289,26 @@ class LiveInformation { print("Audios: ${announcement.audioSources.length}"); return; + } else if (announcement is ManualAnnouncementEntry) { + + List audioSources = []; + + for (String filename in announcement.audioFileNames) { + audioSources.add(AudioWrapperByteSource(announcementCache[filename])); + } + + announcementQueue.add( + ManualAnnouncementEntry( + shortName: announcement.shortName, + informationText: announcement.displayText, + audioFileNames: announcement.audioFileNames, + audioSources: audioSources, + sendToServer: false, + ) + ); + + print("Queued manual announcement: ${announcement.displayText} (no server)"); + return; } announcementQueue.add(announcement); @@ -323,35 +349,13 @@ class LiveInformation { // 5 sedonds in the future DateTime scheduledTime = (await getNow()).add(Duration(seconds: 1)); - print("debug2"); - - List audioFileNames = []; - - for (AudioWrapperSource source in announcement.audioSources) { - - if (source is AudioWrapperByteSource) { - Uint8List? bytes = await source.bytes; - - String? filename = null; - - for (String key in announcementCache.keys) { - if (announcementCache[key] == bytes) { - filename = key; - break; - } - } - - } - - } - final document = databases.createDocument( documentId: appwrite.ID.unique(), databaseId: ApiConstants.INFO_Q_DATABASE_ID, collectionId: ApiConstants.MANUAL_Q_COLLECTION_ID, data: { "DisplayText": announcement.displayText, - "AudioFileNames": audioFileNames, + "AudioFileNames": announcement.audioFileNames, "ScheduledTime": scheduledTime.toIso8601String(), "SessionID": sessionID, @@ -603,47 +607,6 @@ class LiveInformation { } } - // Pull the manual queue - { - final manual_q = await databases.listDocuments( - databaseId: ApiConstants.INFO_Q_DATABASE_ID, - collectionId: ApiConstants.MANUAL_Q_COLLECTION_ID, - queries: [ - appwrite.Query.search("SessionID", sessionID), - appwrite.Query.limit(25), - appwrite.Query.offset(0), - appwrite.Query.orderDesc('\$createdAt') - ] - ); - - for (models.Document doc in manual_q.documents) { - - List audioSources = []; - - for (String filename in doc.data["AudioFileNames"]) { - audioSources.add(AudioWrapperByteSource(announcementCache[filename])); - } - - ManualAnnouncementEntry announcement_clone = - ManualAnnouncementEntry( - sendToServer: false, - - shortName: "", - informationText: doc.data["DisplayText"], - - audioSources: [...audioSources], - scheduledTime: doc.data["ScheduledTime"] != null - ? DateTime.parse(doc.data["ScheduledTime"]) - : null, - - ); - - // sort the queue by timestamp, so the oldest announcements are at the front - - queue.add(announcement_clone); - } - } - // pull the destination queue { final dest_q = await databases.listDocuments( @@ -681,6 +644,45 @@ class LiveInformation { } } + // Pull the manual queue + { + final manual_q = await databases.listDocuments( + databaseId: ApiConstants.INFO_Q_DATABASE_ID, + collectionId: ApiConstants.MANUAL_Q_COLLECTION_ID, + queries: [ + appwrite.Query.search("SessionID", sessionID), + appwrite.Query.limit(25), + appwrite.Query.offset(0), + appwrite.Query.orderDesc('\$createdAt') + ] + ); + + for (models.Document doc in manual_q.documents) { + + + + List audioFileNames = doc.data["AudioFileNames"].cast(); + + ManualAnnouncementEntry announcement_clone = + ManualAnnouncementEntry( + sendToServer: false, + + shortName: "", + informationText: doc.data["DisplayText"], + audioFileNames: audioFileNames, + + scheduledTime: doc.data["ScheduledTime"] != null + ? DateTime.parse(doc.data["ScheduledTime"]) + : null, + + ); + + // sort the queue by timestamp, so the oldest announcements are at the front + + queue.add(announcement_clone); + } + } + for (AnnouncementQueueEntry entry in queue) { // Dont queue announcements that are older than now @@ -749,6 +751,7 @@ class LiveInformation { manual_q_subscription = null; destination_q_subscription?.close(); destination_q_subscription = null; + print("Restarting realtime"); setupRealtime(); } @@ -788,11 +791,13 @@ class NamedAnnouncementQueueEntry extends AnnouncementQueueEntry { class ManualAnnouncementEntry extends NamedAnnouncementQueueEntry { + final List audioFileNames; ManualAnnouncementEntry({ required String shortName, required String informationText, - required List audioSources, + required this.audioFileNames, + List audioSources = const [], DateTime? scheduledTime, DateTime? timestamp, bool sendToServer = true,