This commit is contained in:
ImBenji
2024-05-17 17:38:37 +01:00
6 changed files with 5734 additions and 358 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -39,7 +39,7 @@ class LiveInformation {
// By default, load the bus sequences from the assets // By default, load the bus sequences from the assets
print("Loading bus sequences from assets"); print("Loading bus sequences from assets");
busSequences = BusSequences.fromCSV( busSequences = BusSequences.fromCSV(
await rootBundle.loadString("assets/datasets/bus-blinds.csv"), await rootBundle.loadString("assets/datasets/destinations.json"),
await rootBundle.loadString("assets/datasets/bus-sequences.csv") await rootBundle.loadString("assets/datasets/bus-sequences.csv")
); );
print("Loaded bus sequences from assets"); print("Loaded bus sequences from assets");
@@ -49,7 +49,7 @@ class LiveInformation {
http.Response response = await http.get(Uri.parse('https://tfl.gov.uk/bus-sequences.csv')); http.Response response = await http.get(Uri.parse('https://tfl.gov.uk/bus-sequences.csv'));
busSequences = BusSequences.fromCSV( busSequences = BusSequences.fromCSV(
await rootBundle.loadString("assets/datasets/bus-blinds.csv"), await rootBundle.loadString("assets/datasets/destinations.json"),
response.body response.body
); );
@@ -294,7 +294,7 @@ class LiveInformation {
print("Created room with code $roomCode"); print("Created room with code $roomCode");
} }
Future<void> JoinRoom(String roomCode) async { Future<void> joinRoom(String roomCode) async {
print("Joining room with code $roomCode"); print("Joining room with code $roomCode");
// Disable host mode // Disable host mode
@@ -375,6 +375,45 @@ class LiveInformation {
print("Joined room with code $roomCode"); print("Joined room with code $roomCode");
} }
Future<void> leaveRoom() async {
if (roomCode == null) {
throw Exception("Not in a room");
}
if (isHost) {
// Access the database
final client = auth.client;
final databases = appwrite.Databases(client);
// Remove any existing documents
final existingDocuments = await databases.listDocuments(
databaseId: "6633e85400036415ab0f",
collectionId: "6633e85d0020f52f3771",
queries: [
appwrite.Query.search("SessionID", roomCode!)
]
);
for (var document in existingDocuments.documents) {
await databases.deleteDocument(
databaseId: "6633e85400036415ab0f",
collectionId: "6633e85d0020f52f3771",
documentId: document.$id
);
}
}
roomCode = null;
roomDocumentID = null;
isHost = false;
_keepAliveConnection?.close();
_keepAliveConnection = null;
// Reset stuff
setRouteVariant(null);
}
String? lastCommand; String? lastCommand;
Future<void> ServerListener(appwrite.RealtimeMessage response) async { Future<void> ServerListener(appwrite.RealtimeMessage response) async {
print("Session update"); print("Session update");

View File

@@ -175,7 +175,7 @@ class AnnouncementModule extends InfoModule {
bool sendToServer = true bool sendToServer = true
}) async { }) async {
if (sendToServer) { if (sendToServer && _shouldSendToServer()) {
scheduledTime ??= liveInformation.syncedTimeModule.Now().add(Duration(seconds: defaultAnnouncementDelay)); scheduledTime ??= liveInformation.syncedTimeModule.Now().add(Duration(seconds: defaultAnnouncementDelay));
@@ -230,7 +230,7 @@ class AnnouncementModule extends InfoModule {
bool sendToServer = true bool sendToServer = true
}) { }) {
if (sendToServer) { if (sendToServer && _shouldSendToServer()) {
scheduledTime ??= liveInformation.syncedTimeModule.Now().add(Duration(seconds: defaultAnnouncementDelay)); scheduledTime ??= liveInformation.syncedTimeModule.Now().add(Duration(seconds: defaultAnnouncementDelay));
@@ -260,7 +260,7 @@ class AnnouncementModule extends InfoModule {
bool sendToServer = true bool sendToServer = true
}) async { }) async {
if (sendToServer) { if (sendToServer && _shouldSendToServer()) {
scheduledTime ??= liveInformation.syncedTimeModule.Now().add(Duration(seconds: defaultAnnouncementDelay)); scheduledTime ??= liveInformation.syncedTimeModule.Now().add(Duration(seconds: defaultAnnouncementDelay));
@@ -324,6 +324,14 @@ class AnnouncementModule extends InfoModule {
queue.add(announcement); queue.add(announcement);
} }
// Server check
bool _shouldSendToServer() {
bool condition = liveInformation.roomCode != null;
print("Should send to server? " + (condition.toString()));
return condition;
}
// Constants // Constants
final List<NamedAnnouncementQueueEntry> manualAnnouncements = [ final List<NamedAnnouncementQueueEntry> manualAnnouncements = [

View File

@@ -231,7 +231,7 @@ class RoutePage extends StatelessWidget {
], ],
), ),
if (!kIsWeb)
Text( Text(
"Nearby routes", "Nearby routes",
style: ShadTheme.of(context).textTheme.h4, style: ShadTheme.of(context).textTheme.h4,
@@ -649,11 +649,23 @@ class _dash extends StatelessWidget {
], ],
), ),
), ),
) ),
// SizedBox( SizedBox(
// height: 8, height: 8,
// ), ),
Container(
padding: const EdgeInsets.all(8),
child: ShadButton(
text: const Text("Fullscreen display"),
onPressed: () {
Navigator.pushNamed(context, "/display");
},
icon: const Icon(Icons.fullscreen),
width: double.infinity,
),
),
// //
// ShadCard( // ShadCard(
// title: Text("Stop announcements"), // title: Text("Stop announcements"),
@@ -961,94 +973,35 @@ class _MultiModeEnrouteState extends State<MultiModeEnroute> {
LiveInformation liveInformation = LiveInformation(); LiveInformation liveInformation = LiveInformation();
return Scaffold( return PopScope(
canPop: false,
onPopInvoked: (didPop) {
body: Column( if (didPop){
children: [ print("Compensating for pop");
liveInformation.leaveRoom();
return;
}
Container( // return;
padding: const EdgeInsets.all(16), // Ask the user to confirm if they want to leave the group
height: 200,
child: ShadCard(
title: liveInformation.isHost ? const Text("Hosting group") : const Text("Joined group"),
border: Border.all(
color: Colors.amber,
width: 1
),
padding: const EdgeInsets.all(16),
width: double.infinity,
description: liveInformation.isHost ? const Text(
"You are hosting a group. \nShare the room code with others to join"
) : const Text(
"You have joined a group."
),
content: Column(
children: [
const SizedBox(
height: 4,
),
FutureBuilder(
future: Future.delayed(const Duration(seconds: 1)),
builder: (context, snapshot) {
return Row(
children: [
Expanded(
child: ShadButton(
text: Text(
liveInformation.roomCode!,
),
icon: const Icon(Icons.copy),
padding: const EdgeInsets.all(8),
onPressed: () {
Clipboard.setData(ClipboardData(text: liveInformation.roomCode!));
ShadToaster.of(context).show(
const ShadToast(
title: Text("Copied to clipboard"),
description: Text("Room code copied to clipboard"),
duration: Duration(seconds: 5),
)
);
},
),
),
ShadButton(
icon: const Icon(Icons.qr_code),
onPressed: () {
showShadDialog( showShadDialog(
context: context, context: context,
builder: (context) { builder: (context) {
return ShadDialog( return ShadDialog(
title: const Text("QR Code"), title: const Text("Leave group?"),
content: Container( content: const Text("Are you sure you want to leave the group?"),
width: 200,
height: 225,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
QrImageView(
data: liveInformation.roomCode!,
size: 200,
backgroundColor: Colors.white,
),
const SizedBox(
height: 8,
),
Text("Scan QR code to join the group")
],
),
),
actions: [ actions: [
ShadButton( ShadButton(
text: const Text("Close"), text: const Text("Leave"),
onPressed: () {
liveInformation.leaveRoom();
Navigator.pop(context);
Navigator.pop(context);
},
),
ShadButton(
text: const Text("Cancel"),
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
}, },
@@ -1057,17 +1010,13 @@ class _MultiModeEnrouteState extends State<MultiModeEnroute> {
); );
} }
); );
},
)
],
);
},
),
],
),
),
),
},
child: Scaffold(
body: Column(
children: [
const Divider( const Divider(
height: 1, height: 1,
), ),
@@ -1121,6 +1070,7 @@ class _MultiModeEnrouteState extends State<MultiModeEnroute> {
children: [ children: [
if (!kIsWeb)
Container( Container(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
top: 4, top: 4,
@@ -1313,6 +1263,112 @@ class _MultiModeEnrouteState extends State<MultiModeEnroute> {
width: double.infinity, width: double.infinity,
), ),
), ),
const Divider(
height: 1,
),
Container(
padding: const EdgeInsets.all(16),
// height: 200,
child: ShadCard(
title: liveInformation.isHost ? const Text("Currently hosting group") : const Text("Successfully joined group"),
border: Border.all(
color: Colors.amber,
width: 1
),
padding: const EdgeInsets.all(16),
width: double.infinity,
description: liveInformation.isHost ? const Text(
"You are hosting a group. \nShare the room code with others to join"
) : const Text(
"You have joined a group."
),
content: Column(
children: [
const SizedBox(
height: 4,
),
FutureBuilder(
future: Future.delayed(const Duration(seconds: 1)),
builder: (context, snapshot) {
return Row(
children: [
Expanded(
child: ShadButton(
text: Text(
liveInformation.roomCode!,
),
icon: const Icon(Icons.copy),
padding: const EdgeInsets.all(8),
onPressed: () {
Clipboard.setData(ClipboardData(text: liveInformation.roomCode!));
ShadToaster.of(context).show(
const ShadToast(
title: Text("Copied to clipboard"),
description: Text("Room code copied to clipboard"),
duration: Duration(seconds: 5),
)
);
},
),
),
ShadButton(
icon: const Icon(Icons.qr_code),
onPressed: () {
showShadDialog(
context: context,
builder: (context) {
return ShadDialog(
title: const Text("QR Code"),
content: Container(
width: 200,
height: 225,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
QrImageView(
data: liveInformation.roomCode!,
size: 200,
backgroundColor: Colors.white,
),
const SizedBox(
height: 8,
),
Text("Scan QR code to join the group")
],
),
),
actions: [
ShadButton(
text: const Text("Close"),
onPressed: () {
Navigator.pop(context);
},
)
],
);
}
);
},
)
],
);
},
),
],
),
),
),
const Divider( const Divider(
height: 1, height: 1,
), ),
@@ -1320,6 +1376,7 @@ class _MultiModeEnrouteState extends State<MultiModeEnroute> {
], ],
), ),
),
); );
} }
@@ -1377,7 +1434,7 @@ class _MultiModeJoinState extends State<MultiModeJoin> {
liveInformation.setRouteVariant(null); liveInformation.setRouteVariant(null);
await liveInformation.JoinRoom(controller.text); await liveInformation.joinRoom(controller.text);
Navigator.popAndPushNamed(context, "/multi/enroute"); Navigator.popAndPushNamed(context, "/multi/enroute");
@@ -1773,6 +1830,11 @@ class MultiModeRegister extends StatelessWidget {
} }
class NavigationBar extends StatefulWidget { class NavigationBar extends StatefulWidget {
final Widget? content;
NavigationBar({this.content = null});
@override @override
State<NavigationBar> createState() => _NavigationBarState(); State<NavigationBar> createState() => _NavigationBarState();
} }
@@ -1825,7 +1887,7 @@ List<Widget> _getNearbyRoutes({bool multiMode = false}) {
if (kDebugMode) { if (kDebugMode) {
currentVector = OSGrid.toNorthingEasting(51.583781262560926, -0.020359583104595073); // currentVector = OSGrid.toNorthingEasting(51.583781262560926, -0.020359583104595073);
} }
for (BusRoute route in busSequences.routes.values) { for (BusRoute route in busSequences.routes.values) {

View File

@@ -1,5 +1,6 @@
import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:bus_infotainment/audio_cache.dart'; import 'package:bus_infotainment/audio_cache.dart';
@@ -16,28 +17,24 @@ class BusSequences extends InfoModule {
Map<String, BusDestination> destinations = {}; Map<String, BusDestination> destinations = {};
BusSequences.fromCSV(String destinationsCSV, String busSequencesCSV) { BusSequences.fromCSV(String destinationsJson, String busSequencesCSV) {
// Init the bus destinations // Init the bus destinations
List<List<String>> destinationRows = CsvConverter().convert(destinationsCSV); Map<String, dynamic> destinationData = jsonDecode(destinationsJson);
destinationRows.removeAt(0);
print("Destination rows: ${destinationRows.length}"); print("Destination rows: ${destinationData.length}");
for (int i = 0; i < destinationRows.length; i++) { for (String destinationName in destinationData.keys) {
try { try {
Map<String, dynamic> destinationDetails = destinationData[destinationName];
List<dynamic> entries = destinationRows[i]; String blind = destinationName;
// print("Parsing destination row $i: $entries");
String routeNumber = entries[0].toString(); List<String> location = destinationDetails['Location'].split(', ');
double lat = double.parse(location[0]);
BusRoute route = routes.containsKey(routeNumber) ? routes[routeNumber]! : BusRoute(routeNumber: routeNumber); double long = double.parse(location[1]);
String blind = entries[1].toString();
double lat = double.parse(entries[2].toString());
double long = double.parse(entries[3].toString());
Vector2 grid = OSGrid.toNorthingEasting(lat, long); Vector2 grid = OSGrid.toNorthingEasting(lat, long);
@@ -46,11 +43,10 @@ class BusSequences extends InfoModule {
destination.easting = grid.x; destination.easting = grid.x;
destination.northing = grid.y; destination.northing = grid.y;
route.destinations.add(destination);
routes[routeNumber] = route;
destinations[blind] = destination; destinations[blind] = destination;
} catch (e) {} } catch (e) {
print("Error parsing destination: $e");
}
} }
print("Loaded ${destinations.length} destinations"); print("Loaded ${destinations.length} destinations");

View File

@@ -97,6 +97,7 @@ flutter:
- assets/datasets/tube_stations.json - assets/datasets/tube_stations.json
- assets/audio/rail_replacement/ - assets/audio/rail_replacement/
- assets/audio/R_SPECIAL_SERVICE_001.mp3 - assets/audio/R_SPECIAL_SERVICE_001.mp3
- assets/datasets/destinations.json
# - images/a_dot_burr.jpeg # - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg # - images/a_dot_ham.jpeg