import 'dart:async'; import 'package:bus_infotainment/pages/components/ibus_display.dart'; import 'package:bus_infotainment/backend/live_information.dart'; import 'package:bus_infotainment/tfl_datasets.dart'; import 'package:bus_infotainment/utils/OrdinanceSurveyUtils.dart'; import 'package:bus_infotainment/utils/audio%20wrapper.dart'; import 'package:bus_infotainment/utils/delegates.dart'; import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; import 'package:google_fonts/google_fonts.dart'; class pages_Home extends StatelessWidget { const pages_Home({super.key}); @override Widget build(BuildContext context) { return Container( child: Column( children: [ Row( children: [ Speedometer(), ], ), Container( height: 2, color: Colors.white70, ), SingleChildScrollView( child: Column( children: [ Container( margin: EdgeInsets.all(10), child: Container( decoration: BoxDecoration( color: Colors.grey.shade900, ), child: AnnouncementPicker( backgroundColor: Colors.grey.shade900, outlineColor: Colors.white70, announcements: [ for (NamedAnnouncementQueueEntry announcement in LiveInformation().announcementModule.manualAnnouncements) _AnnouncementEntry( label: announcement.shortName, index: LiveInformation().announcementModule.manualAnnouncements.indexOf(announcement), outlineColor: Colors.white70, onPressed: (){ LiveInformation liveInformation = LiveInformation(); liveInformation.announcementModule.queueAnnounementByInfoIndex( infoIndex: liveInformation.announcementModule.manualAnnouncements.indexOf(announcement), sendToServer: true ); }, ) ], ), ), ), Container( height: 2, color: Colors.white70, ), Container( margin: EdgeInsets.all(10), child: Container( decoration: BoxDecoration( color: Colors.grey.shade900, ), 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, ); } }, ), ), ), ElevatedButton( onPressed: () async { LiveInformation liveInformation = LiveInformation(); final commandModule = liveInformation.commandModule; // commandModule.executeCommand( // "announce dest" // ); liveInformation.announcementModule.queueAnnouncementByRouteVariant( routeVariant: liveInformation.getRouteVariant()! ); }, child: Text("Announce current 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"), // ), // // ], // // ), // // ), ], ), ), ], ) ); } } class Speedometer extends StatefulWidget { @override State createState() => _SpeedometerState(); } class _SpeedometerState extends State { double speed = 0; double arrivalTime = 0; BusRouteStop? nearestStop; double speed2 = 0; _SpeedometerState(){ } @override void initState() { // TODO: implement initState super.initState(); Timer.periodic(Duration(milliseconds: 250), (timer) { Position? newPosition = LiveInformation().trackerModule.position; speed = newPosition?.speed ?? 0; arrivalTime -= 0.25; arrivalTime = arrivalTime < 0 ? 0 : arrivalTime; setState(() { }); }); } @override Widget build(BuildContext context) { // TODO: implement build return Container( margin: EdgeInsets.all(8), height: 74, child: Row( children: [ Container( // width: 60, height: double.infinity, alignment: Alignment.center, decoration: BoxDecoration( border: Border.all( color: Colors.white70, width: 2 ) ), padding: const EdgeInsets.all(8), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( decoration: BoxDecoration( border: Border.all( color: Colors.white70, width: 2 ) ), width: 30, height: 30, alignment: Alignment.center, child: Text( "${((speed) * 2.237).toInt()}", style: GoogleFonts.teko( fontSize: 20, color: Colors.white70, height: 1 ), ) ), const SizedBox( height: 4, ), Text( "MPH", style: GoogleFonts.teko( fontSize: 20, color: Colors.white70, height: 1 ), ), ], ), ), ], ), ); } } class AnnouncementPicker extends StatefulWidget { final Color backgroundColor; final Color outlineColor; final List announcements; const AnnouncementPicker({super.key, required this.backgroundColor, required this.outlineColor, required this.announcements}); @override State createState() => _AnnouncementPickerState(); } class _AnnouncementPickerState extends State { List announcementWidgets = []; int _currentIndex = 0; @override void initState() { // TODO: implement initState super.initState(); LiveInformation liveInformation = LiveInformation(); if (widget.announcements.isEmpty){ return; } int i = 0; for (Widget announcement in widget.announcements!) { announcementWidgets.add( announcement ); i++; } } @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( color: widget.backgroundColor, border: Border.all( color: widget.outlineColor, width: 2 ), ), padding: const EdgeInsets.all(4), width: double.infinity, constraints: const BoxConstraints( maxWidth: 400 ), child: Column( children: [ Container( height: 2, color: widget.outlineColor, ), if (_currentIndex < announcementWidgets.length) announcementWidgets[_currentIndex + 0] else Container( height: 50, decoration: BoxDecoration( color: widget.backgroundColor, border: Border.symmetric( vertical: BorderSide( color: widget.outlineColor, width: 2 ) ), ), ), Container( height: 2, color: widget.outlineColor, ), if (_currentIndex + 1 < announcementWidgets.length) announcementWidgets[_currentIndex + 1] else Container( height: 50, decoration: BoxDecoration( color: widget.backgroundColor, border: Border.symmetric( vertical: BorderSide( color: widget.outlineColor, width: 2 ) ), ), ), Container( height: 2, color: widget.outlineColor, ), if (_currentIndex + 2 < announcementWidgets.length) announcementWidgets[_currentIndex + 2] else Container( height: 50, decoration: BoxDecoration( color: widget.backgroundColor, border: Border.symmetric( vertical: BorderSide( color: widget.outlineColor, width: 2 ) ), ), ), Container( height: 2, color: widget.outlineColor, ), if (_currentIndex + 3 < announcementWidgets.length) announcementWidgets[_currentIndex + 3] else Container( height: 50, decoration: BoxDecoration( color: widget.backgroundColor, border: Border.symmetric( vertical: BorderSide( color: widget.outlineColor, width: 2 ) ), ), ), Container( height: 2, color: widget.outlineColor, ), Container( height: 40, decoration: BoxDecoration( color: widget.backgroundColor, border: Border.symmetric( vertical: BorderSide( color: widget.outlineColor, width: 2 ) ), ), alignment: Alignment.centerRight, child: Row( mainAxisSize: MainAxisSize.min, children: [ Container( width: 40, height: 40, decoration: BoxDecoration( color: widget.backgroundColor, border: Border.symmetric( vertical: BorderSide( color: widget.outlineColor, width: 2 ) ), ), margin: const EdgeInsets.symmetric( horizontal: 4 ), child: Container( child: Stack( children: [ Container( width: 40, height: 40, child: Icon( Icons.arrow_upward, color: widget.outlineColor, ), ), Positioned.fill( child: ElevatedButton( onPressed: () { _currentIndex = wrap(_currentIndex - 4, 0, announcementWidgets.length, increment: 4); setState(() {}); print(_currentIndex); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.transparent, shadowColor: Colors.transparent, surfaceTintColor: Colors.transparent, foregroundColor: Colors.transparent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0), ), ), child: const Text(""), ), ) ], ), ) ), Container( width: 40, height: 40, decoration: BoxDecoration( color: widget.backgroundColor, border: Border.symmetric( vertical: BorderSide( color: widget.outlineColor, width: 2 ) ), ), margin: const EdgeInsets.symmetric( horizontal: 4 ), child: Container( child: Stack( children: [ Container( width: 40, height: 40, child: Icon( Icons.arrow_downward, color: widget.outlineColor, ), ), Positioned.fill( child: ElevatedButton( onPressed: () { _currentIndex = wrap(_currentIndex + 4, 0, announcementWidgets.length, increment: 4); setState(() {}); print(_currentIndex); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.transparent, shadowColor: Colors.transparent, surfaceTintColor: Colors.transparent, foregroundColor: Colors.transparent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0), ), ), child: const Text(""), ), ) ], ), ) ), ] ), ), Container( height: 2, color: widget.outlineColor, ), ] ), ); } } class StopAnnouncementPicker extends AnnouncementPicker { final BusRouteVariant routeVariant; StopAnnouncementPicker({ Key? key, required this.routeVariant, required Color backgroundColor, required Color outlineColor, }) : super( key: key, backgroundColor: backgroundColor, outlineColor: outlineColor, announcements: [ for (BusRouteStop stop in routeVariant.busStops) _AnnouncementEntry( label: stop.formattedStopName, onPressed: () { LiveInformation liveInformation = LiveInformation(); liveInformation.announcementModule.queueAnnounceByAudioName( displayText: stop.formattedStopName, audioNames: [stop.getAudioFileName()], ); }, index: routeVariant.busStops.indexOf(stop), outlineColor: outlineColor, alert: LiveInformation().announcementModule.announcementCache[stop.getAudioFileName()] == null, ) ] ); } int wrap(int i, int j, int length, {int increment = -1}) { if (increment == -1) { return ((i - j) % length + length) % length; } else { if (i >= length) { return 0; } else if (i < 0) { double d = length / increment; int n = d.toInt(); return (n-1) * increment; } else { return i; } } } class _AnnouncementEntry extends StatelessWidget { final String label; final Function onPressed; final int index; final Color outlineColor; bool alert = false; _AnnouncementEntry({super.key, required this.label, required this.onPressed, required this.index, required this.outlineColor, this.alert = false}); @override Widget build(BuildContext context) { return Stack( children: [ Container( decoration: BoxDecoration( color: Colors.transparent, border: Border.symmetric( vertical: BorderSide( color: outlineColor, width: 2 ) ), ), padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 5 ), width: double.infinity, child: Row( children: [ Row( children: [ Container( constraints: const BoxConstraints( maxWidth: 260 ), child: Text( label, style: GoogleFonts.teko( fontSize: 25, color: outlineColor, ), overflow: TextOverflow.ellipsis, ), ), if (alert) const SizedBox( width: 4, ), if (alert) Icon( Icons.error, color: Colors.red.shade800, size: 25, shadows: const [ Shadow( color: Colors.black, blurRadius: 2, ) ], ) ], ), Expanded( child: Container( alignment: Alignment.centerRight, child: Text( (index+1).toString(), style: GoogleFonts.teko( fontSize: 25, color: outlineColor, ) ), ), ) ], ) ), Positioned.fill( child: ElevatedButton( onPressed: () { onPressed(); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.transparent, shadowColor: Colors.transparent, surfaceTintColor: Colors.transparent, foregroundColor: Colors.transparent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0), ), ), child: const Text("More"), ), ) ], ); } }