This commit is contained in:
ImBenji
2024-05-17 17:38:34 +01:00
parent 1f48f8f4b0
commit 3556639acc
10 changed files with 636 additions and 49 deletions

View File

@@ -433,7 +433,7 @@ class LiveInformation {
if (mode == "info") {
print("Announce info command received");
announcementModule.queueAnnounementByInfoIndex(
announcementModule.queueAnnouncementByInfoIndex(
sendToServer: false,
infoIndex: int.parse(commandParts[2]),
scheduledTime: DateTime.fromMillisecondsSinceEpoch(int.parse(commandParts[3])),

View File

@@ -224,7 +224,7 @@ class AnnouncementModule extends InfoModule {
}
void queueAnnounementByInfoIndex({
void queueAnnouncementByInfoIndex({
int infoIndex = -1,
DateTime? scheduledTime = null,
bool sendToServer = true
@@ -235,7 +235,7 @@ class AnnouncementModule extends InfoModule {
scheduledTime ??= liveInformation.syncedTimeModule.Now().add(Duration(seconds: defaultAnnouncementDelay));
liveInformation.SendCommand("announce info $infoIndex ${scheduledTime.millisecondsSinceEpoch}");
queueAnnounementByInfoIndex(
queueAnnouncementByInfoIndex(
infoIndex: infoIndex,
scheduledTime: scheduledTime,
sendToServer: false

View File

@@ -144,7 +144,7 @@ class CommandModule extends InfoModule {
}
} catch (e) {}
liveInformation.announcementModule.queueAnnounementByInfoIndex(
liveInformation.announcementModule.queueAnnouncementByInfoIndex(
infoIndex: InfoIndex,
scheduledTime: scheduledTime,
sendToServer: false

View File

@@ -26,6 +26,7 @@ class _ibus_displayState extends State<ibus_display> {
late final ListenerReceipt<AnnouncementQueueEntry> _receipt;
_ibus_displayState(){
LiveInformation liveInformation = LiveInformation();
@@ -42,8 +43,12 @@ class _ibus_displayState extends State<ibus_display> {
});
topLine = liveInformation.announcementModule.currentAnnouncement?.displayText ?? liveInformation.announcementModule.defaultText;
}
String _padString(String input){
if (input.length < 30){
@@ -68,6 +73,8 @@ class _ibus_displayState extends State<ibus_display> {
LiveInformation().announcementModule.onAnnouncement.removeListener(_receipt);
super.dispose();
}
@@ -157,25 +164,11 @@ class _ibus_displayState extends State<ibus_display> {
),
Transform.translate(
offset: Offset(0, -6),
offset: Offset(0, -3.5),
child: Container(
alignment: Alignment.center,
width: 32*4*3,
child: TextScroll(
_padString(bottomLine),
velocity: Velocity(pixelsPerSecond: Offset(120, 0)),
style: const TextStyle(
fontSize: 20,
color: Colors.orange,
fontFamily: "ibus",
shadows: [
Shadow(
color: Colors.orange,
blurRadius: 5,
),
],
),
),
child: _timeComponent(),
),
),
],
@@ -200,4 +193,90 @@ class _ibus_displayState extends State<ibus_display> {
),
);
}
}
class _timeComponent extends StatefulWidget {
@override
State<_timeComponent> createState() => _timeComponentState();
}
class _timeComponentState extends State<_timeComponent> {
late Timer timeTimer;
String bottomLine = "";
@override
void initState() {
// TODO: implement initState
super.initState();
bottomLine = _getTime();
timeTimer = Timer.periodic(Duration(seconds: 1), (timer) {
if (mounted){
setState(() {
bottomLine = _getTime();
});
}
});
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
timeTimer.cancel();
}
String _getTime(){
// Get the current time HH:MM AM/PM
DateTime now = DateTime.now();
bool is24Hour = false;
// if 16 then 4...
String timeString = "${now.hour % 12}:${now.minute.toString().padLeft(2, "0")} ${now.hour < 12 ? "AM" : "PM"}";
return timeString;
}
String _padString(String input){
if (input.length < 30){
print("Input is too short");
return input;
}
String prefix = "";
String suffix = "";
for (int i = 0; i < 80; i++){
prefix += " ";
}
input = input.replaceAll("©", "(c)");
return prefix + input + suffix;
}
@override
Widget build(BuildContext context) {
return TextScroll(
_padString(bottomLine),
velocity: Velocity(pixelsPerSecond: Offset(120, 0)),
style: const TextStyle(
fontSize: 20,
color: Colors.orange,
fontFamily: "ibus",
shadows: [
Shadow(
color: Colors.orange,
blurRadius: 5,
),
],
),
);
}
}

View File

@@ -67,7 +67,7 @@ class pages_Home extends StatelessWidget {
outlineColor: Colors.white70,
onPressed: (){
LiveInformation liveInformation = LiveInformation();
liveInformation.announcementModule.queueAnnounementByInfoIndex(
liveInformation.announcementModule.queueAnnouncementByInfoIndex(
infoIndex: liveInformation.announcementModule.manualAnnouncements.indexOf(announcement),
sendToServer: true
);

View File

@@ -0,0 +1,484 @@
import 'package:bus_infotainment/backend/live_information.dart';
import 'package:bus_infotainment/pages/components/ibus_display.dart';
import 'package:bus_infotainment/remaster/dashboard.dart';
import 'package:bus_infotainment/tfl_datasets.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_scroll_shadow/flutter_scroll_shadow.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
class ArcDashboard extends StatefulWidget {
@override
State<ArcDashboard> createState() => _ArcDashboardState();
}
class _ArcDashboardState extends State<ArcDashboard> {
_closeDialogueChecker closeDialogWidget = _closeDialogueChecker();
@override
Widget build(BuildContext context) {
// Force landscape mode
Future.delayed(Duration(seconds: 1), () {
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
]);
});
return Scaffold(
body: Container(
child: Row(
children: [
const SizedBox(
width: 10,
),
Container(
padding: const EdgeInsets.symmetric(
vertical: 10,
),
child: IntrinsicWidth(
child: Column(
children: [
if (LiveInformation().roomDocumentID != null)
Tooltip(
child: ShadButton(
icon: const Icon(Icons.network_check),
width: double.infinity,
onPressed: () {
showShadSheet(
context: context,
builder: (context) {
return ShadSheet(
padding: const EdgeInsets.all(10),
content: Column(
children: [
Text("Room ID: ${LiveInformation().roomDocumentID}"),
],
),
);
}
);
},
),
message: "Room information",
),
SizedBox(
height: 220,
child: RotatedBox(
quarterTurns: 3,
child: Column(
children: [
ShadButton(
text: const Text("Manual Announcements"),
width: double.infinity,
borderRadius: const BorderRadius.all(Radius.circular(10)),
onPressed: () {
List<Widget> announcements = [];
for (var announcement in LiveInformation().announcementModule.manualAnnouncements) {
announcements.add(
ShadButton(
text: SizedBox(
width: 200-42,
child: Text(announcement.shortName),
),
onPressed: () {
if (closeDialogWidget.closeDialog) {
Navigator.pop(context);
}
LiveInformation().announcementModule.queueAnnouncementByInfoIndex(
infoIndex: LiveInformation().announcementModule.manualAnnouncements.indexOf(announcement),
);
},
)
);
}
print(announcements.length);
showShadSheet(
context: context,
side: ShadSheetSide.left,
builder: (context) {
return ShadSheet(
padding: const EdgeInsets.all(0),
content: Container(
height: MediaQuery.of(context).size.height,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 5,
),
Container(
padding: const EdgeInsets.symmetric(
vertical: 10,
),
alignment: Alignment.bottomCenter,
height: double.infinity,
width: 35,
child: RotatedBox(
quarterTurns: 3,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Text(
"Manual Ann'",
style: ShadTheme.of(context).textTheme.h3
),
SizedBox(
width: 16,
),
Container(
width: 1,
height: 200,
color: Colors.grey,
),
],
),
closeDialogWidget
],
),
),
),
Container(
// width: 220,
height: MediaQuery.of(context).size.height,
child: Scrollbar(
thumbVisibility: true,
child: SingleChildScrollView(
reverse: true,
child: Container(
margin: const EdgeInsets.fromLTRB(
0,
10,
10,
10
),
child: Column(
children: announcements.reversed.toList(),
),
),
),
),
),
],
),
),
);
}
);
},
),
ShadButton(
text: const Text("Bus Stop Announcements"),
width: double.infinity,
borderRadius: const BorderRadius.all(Radius.circular(10)),
onPressed: () {
showShadSheet(
context: context,
side: ShadSheetSide.left,
builder: (context) {
List<Widget> announcements = [];
LiveInformation info = LiveInformation();
for (var busStop in info.getRouteVariant()!.busStops) {
if (info.trackerModule.nearestStop == busStop) {
announcements.add(
ShadButton(
text: SizedBox(
width: 200-42,
child: Text(
"-> ${busStop.formattedStopName}",
overflow: TextOverflow.ellipsis,
),
),
backgroundColor: Colors.amber,
onPressed: () {
if (closeDialogWidget.closeDialog) {
Navigator.pop(context);
}
LiveInformation().announcementModule.queueAnnounceByAudioName(
displayText: busStop.formattedStopName,
audioNames: [busStop.getAudioFileName()],
);
},
)
);
} else {
announcements.add(
ShadButton(
text: SizedBox(
width: 200-42,
child: Text(
busStop.formattedStopName,
overflow: TextOverflow.ellipsis,
),
),
onPressed: () {
if (closeDialogWidget.closeDialog) {
Navigator.pop(context);
}
LiveInformation().announcementModule.queueAnnounceByAudioName(
displayText: busStop.formattedStopName,
audioNames: [busStop.getAudioFileName()],
);
},
)
);
}
}
ScrollController controller = ScrollController();
// Scroll to the current bus stop
WidgetsBinding.instance!.addPostFrameCallback((_) {
double offset = (info.getRouteVariant()!.busStops.indexOf(info.trackerModule.nearestStop!) * 50);
// Offset the offset so that its in the middle of the screen
offset -= (MediaQuery.of(context).size.height / 2) - 25;
// controller.jumpTo(offset);
});
return ShadSheet(
padding: const EdgeInsets.all(0),
content: Container(
height: MediaQuery.of(context).size.height,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 5,
),
Container(
padding: const EdgeInsets.symmetric(
vertical: 10,
),
alignment: Alignment.bottomCenter,
height: double.infinity,
width: 35,
child: RotatedBox(
quarterTurns: 3,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Text(
"Bus Stops",
style: ShadTheme.of(context).textTheme.h3
),
SizedBox(
width: 16,
),
Container(
width: 1,
height: 200,
color: Colors.grey,
),
],
),
closeDialogWidget
],
),
),
),
Container(
// width: 220,
height: MediaQuery.of(context).size.height,
child: Scrollbar(
thumbVisibility: true,
controller: controller,
child: SingleChildScrollView(
reverse: true,
controller: controller,
child: Container(
margin: const EdgeInsets.fromLTRB(
0,
10,
10,
10
),
child: Column(
children: announcements.reversed.toList(),
),
),
),
),
),
],
),
),
);
}
);
},
),
],
)
)
),
const ShadButton(
icon: Icon(Icons.stop),
width: double.infinity,
),
ShadButton(
// text: const Text("Announce Destination"),
icon: const Icon(Icons.location_on),
width: double.infinity,
borderRadius: const BorderRadius.all(Radius.circular(10)),
onPressed: () {
LiveInformation info = LiveInformation();
BusRouteVariant? routeVariant = info.getRouteVariant();
if (routeVariant != null) {
info.announcementModule.queueAnnouncementByRouteVariant(
routeVariant: routeVariant,
sendToServer: false
);
}
},
)
],
),
),
),
Expanded(
child: Container(
decoration: const BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.all(Radius.circular(10)),
),
margin: const EdgeInsets.all(10),
padding: const EdgeInsets.all(10),
width: double.infinity,
height: double.infinity,
child: Stack(
children: [
Container(
alignment: Alignment.center,
child: ibus_display(
hasBorder: false,
),
),
Container(
alignment: Alignment.bottomRight,
child: ShadButton.ghost(
icon: const Icon(Icons.fullscreen),
padding: const EdgeInsets.all(8),
onPressed: () {
Navigator.pushNamed(context, '/display');
},
),
),
Container(
alignment: Alignment.bottomLeft,
child: ShadButton.ghost(
icon: const Icon(Icons.arrow_back),
padding: const EdgeInsets.all(8),
onPressed: () {
Navigator.pop(context);
},
),
)
],
),
),
)
],
),
),
);
}
}
class _closeDialogueChecker extends StatefulWidget {
bool closeDialog = false;
@override
State<_closeDialogueChecker> createState() => _closeDialogueCheckerState();
}
class _closeDialogueCheckerState extends State<_closeDialogueChecker> {
@override
Widget build(BuildContext context) {
// TODO: implement build
return ShadSwitch(
value: widget.closeDialog,
enabled: true,
label: const Text("Close Dialog?"),
onChanged: (value) {
widget.closeDialog = value;
setState(() {
});
},
);
}
}

View File

@@ -2,6 +2,7 @@
import 'package:bus_infotainment/pages/tfl_dataset_test.dart';
import 'package:bus_infotainment/remaster/DashboardArc.dart';
import 'package:bus_infotainment/remaster/InitialStartup.dart';
import 'package:bus_infotainment/remaster/dashboard.dart';
import 'package:flutter/material.dart';
@@ -15,7 +16,12 @@ class RemasteredApp extends StatelessWidget {
return ShadApp(
darkTheme: ShadThemeData(
brightness: Brightness.dark,
colorScheme: ShadSlateColorScheme.dark(),
colorScheme: ShadSlateColorScheme.dark(
background: Colors.grey.shade900,
primary: Colors.grey.shade50,
primaryForeground: Colors.grey.shade900,
border: Colors.grey.shade900,
),
// force dark mode
),
themeMode: ThemeMode.dark,
@@ -24,10 +30,10 @@ class RemasteredApp extends StatelessWidget {
'/setup': (context) => InitialStartup(),
'/': (context) => HomePage_Re(),
'/routes': (context) => RoutePage(),
'/enroute': (context) => EnRoutePage(),
'/enroute': (context) => ArcDashboard(),
'/legacy': (context) => TfL_Dataset_Test(),
'/multi': (context) => MultiModeSetup(),
'/multi/enroute': (context) => MultiModeEnroute(),
'/multi/enroute': (context) => ArcDashboard(),
'/multi/login': (context) => MultiModeLogin(),
'/multi/register': (context) => MultiModeRegister(),
'/display': (context) => FullscreenDisplay(),

View File

@@ -733,7 +733,7 @@ class EasyAnnouncementPicker extends StatelessWidget {
label: entry.shortName,
onPressed: () {
LiveInformation liveInformation = LiveInformation();
liveInformation.announcementModule.queueAnnounementByInfoIndex(
liveInformation.announcementModule.queueAnnouncementByInfoIndex(
infoIndex: liveInformation.announcementModule.manualAnnouncements.indexOf(entry),
sendToServer: true
);
@@ -1431,6 +1431,10 @@ class _FullscreenDisplayState extends State<FullscreenDisplay> {
@override
Widget build(BuildContext context) {
// Get the current screen orientation
final Orientation orientation = MediaQuery.of(context).orientation;
// Make the screen landscape
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
@@ -1440,9 +1444,18 @@ class _FullscreenDisplayState extends State<FullscreenDisplay> {
return PopScope(
onPopInvoked: (isPop) {
if (isPop) {
SystemChrome.setPreferredOrientations([
// SystemChrome.setPreferredOrientations([
// DeviceOrientation.portraitUp,
// DeviceOrientation.portraitDown
// ]);
// Set the orientation back to whatever it was before
SystemChrome.setPreferredOrientations(orientation == Orientation.portrait ? [
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown
] : [
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft
]);
}
},
@@ -1460,12 +1473,17 @@ class _FullscreenDisplayState extends State<FullscreenDisplay> {
hasBorder: false,
),
),
ShadButton.ghost(
icon: const Icon(Icons.arrow_back),
padding: const EdgeInsets.all(8),
onPressed: () {
Navigator.pop(context);
},
Container(
alignment: Alignment.bottomRight,
child: ShadButton.ghost(
icon: const Icon(Icons.arrow_back),
padding: const EdgeInsets.all(8),
onPressed: () {
Navigator.pop(context);
},
),
)
],
),

View File

@@ -105,14 +105,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.1"
boxy:
dependency: transitive
description:
name: boxy
sha256: eaa774ff591191b86f2eb8e8eae878aec50604404b74388a27e655cf3aadf758
url: "https://pub.dev"
source: hosted
version: "2.2.0"
characters:
dependency: transitive
description:
@@ -307,6 +299,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.19"
flutter_scroll_shadow:
dependency: "direct main"
description:
name: flutter_scroll_shadow
sha256: c0509c642c5077654301fab1fb2260adc94c82a407c60e64162974b4366e7874
url: "https://pub.dev"
source: hosted
version: "1.2.4"
flutter_shaders:
dependency: transitive
description:
@@ -537,10 +537,10 @@ packages:
dependency: transitive
description:
name: lucide_icons_flutter
sha256: "43b11fa16f243529c538bcb4a1af014c03c177056c0d46039bc4f665320428c6"
sha256: "6126f30f3236acd7744f8535c2756322e72e96e00f5a94c83afde4abcc917bba"
url: "https://pub.dev"
source: hosted
version: "1.0.8"
version: "1.0.9"
matcher:
dependency: transitive
description:
@@ -777,18 +777,18 @@ packages:
dependency: transitive
description:
name: rive
sha256: "95690a0fb4f6e195c53b217ab3cc0e0b0f443c670adbdee9d57d636a36b82b18"
sha256: "255ab7892a77494458846cecee1376a017e64fd6b4130b51ec21424d12ffa6fe"
url: "https://pub.dev"
source: hosted
version: "0.13.2"
version: "0.13.4"
rive_common:
dependency: transitive
description:
name: rive_common
sha256: "3eee68fcab3e0882090cea5a8cf7acea7967f469a34a2580322575603b094435"
sha256: "3a0d95f529d52caef535d8ff32d75629ca37f7ab4707b13c83e9552a322557bc"
url: "https://pub.dev"
source: hosted
version: "0.4.5"
version: "0.4.8"
rxdart:
dependency: transitive
description:
@@ -809,10 +809,10 @@ packages:
dependency: "direct main"
description:
name: shadcn_ui
sha256: df9aedbd18bd60160c1c54717eef47fe4f90422f843070ccbc32786193803f7d
sha256: d0dce618cbceea8fa96cb58d0ae84dc4fef7f1d95f8838123736ef0a88868473
url: "https://pub.dev"
source: hosted
version: "0.4.1"
version: "0.4.6"
shared_preferences:
dependency: "direct main"
description:

View File

@@ -55,7 +55,7 @@ dependencies:
dart_ping: ^9.0.1
native_qr: ^0.0.3
qr_flutter: ^4.1.0
flutter_scroll_shadow: ^1.2.4
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.