diff --git a/Dockerfile b/Dockerfile
index 6c6b147..2bb3d9e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,36 +1,47 @@
-# Install Operating system and dependencies
-FROM ubuntu:20.04
+# Environemnt to install flutter and build web
+FROM debian:latest AS build-env
-ENV DEBIAN_FRONTEND noninteractive
+# install all needed stuff
+RUN apt-get update
+RUN apt-get install -y curl git unzip
-RUN apt-get update
-RUN apt-get install -y curl git wget unzip libgconf-2-4 gdb libstdc++6 libglu1-mesa fonts-droid-fallback lib32stdc++6 python3
-RUN apt-get clean
+# define variables
+ARG FLUTTER_SDK=/usr/local/flutter
+ARG FLUTTER_VERSION=3.19.5
+ARG APP=/app/
-# download Flutter SDK from Flutter Github repo
-RUN git clone https://github.com/flutter/flutter.git /usr/local/flutter
+#clone flutter
+RUN git clone https://github.com/flutter/flutter.git $FLUTTER_SDK
+# change dir to current flutter folder and make a checkout to the specific version
+RUN cd $FLUTTER_SDK && git fetch && git checkout $FLUTTER_VERSION
-# Set flutter environment path
-ENV PATH="/usr/local/flutter/bin:/usr/local/flutter/bin/cache/dart-sdk/bin:${PATH}"
+# setup the flutter path as an enviromental variable
+ENV PATH="$FLUTTER_SDK/bin:$FLUTTER_SDK/bin/cache/dart-sdk/bin:${PATH}"
-# Run flutter doctor
-RUN flutter doctor
+# Start to run Flutter commands
+# doctor to see if all was installes ok
+RUN flutter doctor -v
-# Enable flutter web
-RUN flutter channel master
-RUN flutter upgrade
-RUN flutter config --enable-web
+# create folder to copy source code
+RUN mkdir $APP
+# copy source code to folder
+COPY . $APP
+# stup new folder as the working directory
+WORKDIR $APP
-# Copy files to container and build
-RUN mkdir /app/
-COPY . /app/
-WORKDIR /app/
+# Run build: 1 - clean, 2 - pub get, 3 - build web
+RUN flutter clean
+RUN flutter pub get
RUN flutter build web
-# Record the exposed port
-EXPOSE 5000
+# once heare the app will be compiled and ready to deploy
-# make server startup script executable and start the web server
-RUN ["chmod", "+x", "/app/server/server.sh"]
+# use nginx to deploy
+FROM nginx:1.25.2-alpine
-ENTRYPOINT [ "/app/server/server.sh"]
\ No newline at end of file
+# copy the info of the builded web app to nginx
+COPY --from=build-env /app/build/web /usr/share/nginx/html
+
+# Expose and run nginx
+EXPOSE 80
+CMD ["nginx", "-g", "daemon off;"]
\ No newline at end of file
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 988d667..13f2359 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -25,7 +25,7 @@ if (flutterVersionName == null) {
android {
namespace "com.imbenji.bus_infotainment"
compileSdkVersion 34
- ndkVersion flutter.ndkVersion
+ ndkVersion "25.1.8937393"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 90fc3f8..8d040ad 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -35,5 +35,7 @@
+
+
diff --git a/assets/version.txt b/assets/version.txt
new file mode 100644
index 0000000..d183d4a
--- /dev/null
+++ b/assets/version.txt
@@ -0,0 +1 @@
+0.16.0
\ No newline at end of file
diff --git a/lib/backend/live_information.dart b/lib/backend/live_information.dart
index bf59652..e598910 100644
--- a/lib/backend/live_information.dart
+++ b/lib/backend/live_information.dart
@@ -67,19 +67,17 @@ class LiveInformation {
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();
- }
- });
- }
+ initTrackerModule();
print("Initialised LiveInformation");
}
+ Future initTrackerModule() async {
+ if (await Permission.location.isGranted) {
+ trackerModule = TrackerModule();
+ }
+ }
+
// Auth
AuthAPI auth = AuthAPI();
@@ -120,7 +118,15 @@ class LiveInformation {
// Cache/Load the audio files
await announcementModule
.announcementCache
- .loadAnnouncementsFromBytes(await LiveInformation().announcementModule.getBundleBytes(), audioFiles);
+ .loadAnnouncementsFromBytes(await LiveInformation().announcementModule.getBundleBytes(), [
+ ...audioFiles,
+ if (!routeVariant.busRoute.routeNumber.toLowerCase().startsWith("ul"))
+ "R_${routeVariant.busRoute.routeNumber}_001.mp3"
+ else
+ "R_RAIL_REPLACEMENT_SERVICE_001.mp3",
+
+ ]
+ );
}
// Public methods
diff --git a/lib/backend/modules/announcement.dart b/lib/backend/modules/announcement.dart
index 623c9c9..93da25e 100644
--- a/lib/backend/modules/announcement.dart
+++ b/lib/backend/modules/announcement.dart
@@ -88,10 +88,10 @@ class AnnouncementModule extends InfoModule {
if (currentAnnouncement!.audioSources.isNotEmpty) {
- audioPlayer.loadSource(AudioWrapperAssetSource("assets/audio/5-seconds-of-silence.mp3"));
- audioPlayer.play();
- await Future.delayed(const Duration(milliseconds: 300));
- audioPlayer.stop();
+ // audioPlayer.loadSource(AudioWrapperAssetSource("assets/audio/5-seconds-of-silence.mp3"));
+ // audioPlayer.play();
+ // await Future.delayed(const Duration(milliseconds: 300));
+ // audioPlayer.stop();
// try {
for (AudioWrapperSource source in currentAnnouncement!.audioSources) {
@@ -100,6 +100,8 @@ class AnnouncementModule extends InfoModule {
Duration? duration = await audioPlayer.play();
await Future.delayed(duration!);
+ audioPlayer.stop();
+ // await Future.delayed(const Duration(milliseconds: 100));
if (currentAnnouncement?.audioSources.last != source) {
await Future.delayed(const Duration(milliseconds: 100));
}
@@ -256,25 +258,37 @@ class AnnouncementModule extends InfoModule {
);
return;
}
+ print("Checkpoint 4");
+
+ print(routeVariant);
+ print("Checkpoint 4.1");
+
String routeNumber = routeVariant.busRoute.routeNumber;
- String destination = routeVariant.destination!.destination;
+ print("Checkpoint 4.2");
+
+ String destination = routeVariant.destination?.destination ?? "NullPointerException";
+ print("Destination: $destination");
+ print("Checkpoint 4.3");
+
String audioRoute = "R_${routeVariant.busRoute.routeNumber}_001.mp3";
-
+ print("Checkpoint 5");
await announcementCache.loadAnnouncementsFromBytes(await getBundleBytes(), [audioRoute, "R_RAIL_REPLACEMENT_SERVICE_001.mp3"]);
-
+ print("Checkpoint 6");
AudioWrapperSource sourceRoute = !routeNumber.toLowerCase().startsWith("ul") ?
AudioWrapperByteSource(announcementCache[audioRoute]!) :
AudioWrapperByteSource(announcementCache["R_RAIL_REPLACEMENT_SERVICE_001.mp3"]!);
+ print("Checkpoint 6.1");
AudioWrapperSource sourceDestination = AudioWrapperByteSource(await routeVariant.destination!.getAudioBytes());
-
+ print("Checkpoint 7");
AnnouncementQueueEntry announcement = AnnouncementQueueEntry(
displayText: "$routeNumber to $destination",
audioSources: [sourceRoute, AudioWrapperAssetSource("audio/to_destination.wav"), sourceDestination],
scheduledTime: scheduledTime
);
+ print("Checkpoint 8");
queue.add(announcement);
}
diff --git a/lib/backend/modules/commands.dart b/lib/backend/modules/commands.dart
index 516ec20..5be6b25 100644
--- a/lib/backend/modules/commands.dart
+++ b/lib/backend/modules/commands.dart
@@ -129,6 +129,8 @@ class CommandModule extends InfoModule {
else if (args[0].startsWith("dest")) {
// announce destination
+ print("Checkpoint 1");
+
String routeNumber = args[1];
int routeVariantIndex = int.parse(args[2]);
@@ -139,9 +141,11 @@ class CommandModule extends InfoModule {
}
} catch (e) {}
+ print("Checkpoint 2");
BusRoute route = LiveInformation().busSequences.routes[routeNumber]!;
BusRouteVariant routeVariant = route.routeVariants.values.toList()[routeVariantIndex];
+ print("Checkpoint 3");
liveInformation.announcementModule.queueAnnouncementByRouteVariant(
routeVariant: routeVariant,
scheduledTime: scheduledTime,
diff --git a/lib/main.dart b/lib/main.dart
index 1546c82..a301b5d 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -4,10 +4,13 @@ import 'package:bus_infotainment/pages/audio_cache_test.dart';
import 'package:bus_infotainment/pages/initial_startup.dart';
import 'package:bus_infotainment/pages/tfl_dataset_test.dart';
import 'package:bus_infotainment/backend/live_information.dart';
+import 'package:bus_infotainment/remaster/RemasteredMain.dart';
+import 'package:bus_infotainment/remaster/dashboard.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:window_manager/window_manager.dart';
+import 'package:bus_infotainment/remaster/InitialStartup.dart' as remaster;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
@@ -55,14 +58,20 @@ class MyApp extends StatelessWidget {
// Permission.location.onGrantedCallback(() => null).request();
+ if (true) {
+ return RemasteredApp();
+ }
+
print("Window size: ${MediaQuery.of(context).size}");
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
+ useMaterial3: true,
brightness: Brightness.light,
/* light theme settings */
),
darkTheme: ThemeData(
+ useMaterial3: true,
brightness: Brightness.dark,
// colorScheme: ColorScheme.dark(),
colorScheme: ColorScheme.fromSeed(
@@ -77,8 +86,9 @@ class MyApp extends StatelessWidget {
'/home': (context) => const MyHomePage(title: 'Flutter Demo Home Page'),
'/audiocachetest': (context) => AudioCacheTest(),
// '/': (context) => TfL_Dataset_Test(),
- '/': (context) => InitialStartup(),
+ '/': (context) => remaster.InitialStartup(),
'/application': (context) => TfL_Dataset_Test(),
+ '/dashboard': (context) => Dashboard(),
},
);
diff --git a/lib/pages/home.dart b/lib/pages/home.dart
index 8b58eae..7945bed 100644
--- a/lib/pages/home.dart
+++ b/lib/pages/home.dart
@@ -22,204 +22,206 @@ class pages_Home extends StatelessWidget {
- child: Column(
- children: [
-
- Row(
-
- children: [
-
- Speedometer(),
-
- ],
-
- ),
-
- Container(
- height: 2,
- color: Colors.white70,
- ),
-
- SingleChildScrollView(
- child: Column(
+ child: SingleChildScrollView(
+ child: Column(
+ children: [
+
+ Row(
+
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
- );
- },
- )
- ],
+
+ 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 {
+
+ 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"),
- // ),
- //
- // ],
- //
- // ),
- //
- // ),
-
- ],
+
+ 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"),
+ // ),
+ //
+ // ],
+ //
+ // ),
+ //
+ // ),
+
+ ],
+ ),
),
- ),
- ],
+ ],
+ ),
)
);
diff --git a/lib/pages/initial_startup.dart b/lib/pages/initial_startup.dart
index cfdd048..7761f5e 100644
--- a/lib/pages/initial_startup.dart
+++ b/lib/pages/initial_startup.dart
@@ -1,7 +1,12 @@
+import 'dart:convert';
+
+import 'package:bus_infotainment/backend/live_information.dart';
import 'package:bus_infotainment/pages/settings.dart';
import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
+import 'package:shared_preferences/shared_preferences.dart';
class InitialStartup extends StatefulWidget {
@@ -9,11 +14,43 @@ class InitialStartup extends StatefulWidget {
State createState() => _InitialStartupState();
}
-const String Version = "0.2.0";
+// Get the current version from /assets/version.txt
+Future GetVersion() async {
+ return await rootBundle.loadString("assets/version.txt");
+}
class _InitialStartupState extends State {
bool AllowPassage = false;
+
+ @override
+ void initState() {
+ // TODO: implement initState
+ super.initState();
+
+ SharedPreferences.getInstance().then((prefs) {
+ String? base64String = prefs.getString("announcements");
+
+ if (base64String != null) {
+ print("Found previois announcement file");
+ Uint8List ByteList = base64Decode(base64String);
+
+ LiveInformation().announcementModule.setBundleBytes(ByteList);
+
+ Navigator.pushNamed(context, "/application");
+
+
+
+ } else {
+ print("No previous announcement file found");
+ }
+
+ });
+
+
+
+ }
+
@override
Widget build(BuildContext context) {
// TODO: implement build
@@ -28,6 +65,8 @@ class _InitialStartupState extends State {
children: [
+ PermissionsSetup(),
+
SizedBox(
height: 8,
),
@@ -79,13 +118,29 @@ class _InitialStartupState extends State {
height: 8,
),
- Text(
- "Version $Version",
- style: GoogleFonts.inter(
- fontSize: 12,
- fontWeight: FontWeight.w400,
- color: Colors.grey
- ),
+ FutureBuilder(
+ future: GetVersion(),
+ builder: (context, snapshot){
+ if (snapshot.hasData){
+ return Text(
+ "Version ${snapshot.data}",
+ style: GoogleFonts.inter(
+ fontSize: 12,
+ fontWeight: FontWeight.w400,
+ color: Colors.grey
+ ),
+ );
+ } else {
+ return Text(
+ "Version -.-.-",
+ style: GoogleFonts.inter(
+ fontSize: 12,
+ fontWeight: FontWeight.w400,
+ color: Colors.grey
+ ),
+ );
+ }
+ },
)
],
diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart
index 23d0144..1b86d23 100644
--- a/lib/pages/settings.dart
+++ b/lib/pages/settings.dart
@@ -1,5 +1,6 @@
+import 'dart:convert';
import 'dart:io';
import 'package:bus_infotainment/audio_cache.dart';
@@ -7,9 +8,12 @@ import 'package:bus_infotainment/backend/live_information.dart';
import 'package:bus_infotainment/backend/modules/commands.dart';
import 'package:bus_infotainment/utils/delegates.dart';
import 'package:file_picker/file_picker.dart';
+import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
+import 'package:permission_handler/permission_handler.dart';
+import 'package:shared_preferences/shared_preferences.dart';
import 'package:text_scroll/text_scroll.dart';
import 'package:url_launcher/url_launcher_string.dart';
@@ -184,10 +188,24 @@ class _AnnouncementUploadState extends State {
AnnouncementCache cache = LiveInformation().announcementModule.announcementCache;
- LiveInformation().announcementModule.setBundleBytes(result.files[0].bytes!);
+ late Uint8List bytes;
+
+ if (kIsWeb) {
+ bytes = result.files.single.bytes!;
+ } else {
+ File file = File(result.files.single.path!);
+
+ bytes = file.readAsBytesSync();
+ }
+
+
+ LiveInformation().announcementModule.setBundleBytes(bytes);
+
+
+
// load a random announcement to ensure that the file is usable
- await cache.loadAnnouncementsFromBytes(result.files[0].bytes!, ["S_WALTHAMSTOW_CENTRAL_001.mp3"]);
+ await cache.loadAnnouncementsFromBytes(bytes, ["S_WALTHAMSTOW_CENTRAL_001.mp3"]);
print("Loaded announcements");
@@ -195,17 +213,60 @@ class _AnnouncementUploadState extends State {
});
+ if (!kIsWeb) {
+
+ // Use shared preferences to store the file location
+ SharedPreferences prefs = await SharedPreferences.getInstance();
+
+ prefs.setString("AnnouncementsFileLocation", result.files.single.path!);
+ }
+
widget.onUploaded();
} else {
// User canceled the picker
}
+ }
+
+ @override
+ void initState() {
+ // TODO: implement initState
+ super.initState();
+
+ if (!kIsWeb) {
+ SharedPreferences.getInstance().then((prefs) async {
+ String FileLocation = prefs.getString("AnnouncementsFileLocation")!;
+
+ File file = File(FileLocation);
+
+ Uint8List bytes = file.readAsBytesSync();
+
+ LiveInformation().announcementModule.setBundleBytes(bytes);
+
+ AnnouncementCache cache = LiveInformation().announcementModule.announcementCache;
+ await cache.loadAnnouncementsFromBytes(bytes, ["S_WALTHAMSTOW_CENTRAL_001.mp3"]);
+
+ setState(() {
+
+ });
+
+ print("Loaded announcemends from SharedPrefs");
+
+ widget.onUploaded();
+
+ });
+ }
+
+
+
}
@override
Widget build(BuildContext context) {
- // TODO: implement build
+
+ bool checkPassed = LiveInformation().announcementModule.announcementCache.keys.length != 0;
+
return Container(
decoration: BoxDecoration(
border: Border.all(
@@ -224,77 +285,61 @@ class _AnnouncementUploadState extends State {
child: Column(
children: [
+ if (!checkPassed)
+ Row(
- Row(
+ children: [
- children: [
-
- Icon(
- Icons.error,
- color: Colors.red,
- size: 18,
- ),
-
- SizedBox(
- width: 4,
- ),
-
- Transform.translate(
- offset: Offset(0, 0),
- child: Text(
- "IMPORTANT",
- style: GoogleFonts.interTight(
- fontSize: 18,
- fontWeight: FontWeight.bold,
- color: Colors.white70,
- letterSpacing: 0.1,
- ),
- ),
- )
-
- ],
-
- ),
-
- Row(
-
- children: [
-
- if (LiveInformation().announcementModule.announcementCache.keys.length == 0)
Icon(
Icons.error,
color: Colors.red,
size: 18,
- )
- else
+ ),
+
+ SizedBox(
+ width: 4,
+ ),
+
+
+ Transform.translate(
+ offset: Offset(0, 0),
+ child: Text(
+ "NO ANNOUNCEMENTS LOADED",
+ style: GoogleFonts.interTight(
+ fontSize: 18,
+ fontWeight: FontWeight.bold,
+ color: Colors.white70,
+ letterSpacing: 0.1,
+ ),
+ ),
+ )
+
+
+
+
+ ],
+
+ )
+ else
+ Row(
+
+ children: [
+
Icon(
- Icons.check,
+ Icons.check_box,
color: Colors.green,
size: 18,
),
- SizedBox(
- width: 4,
- ),
+ SizedBox(
+ width: 4,
+ ),
+
- if (LiveInformation().announcementModule.announcementCache.keys.length == 0)
Transform.translate(
offset: Offset(0, 0),
child: Text(
- "No announcements",
- style: GoogleFonts.interTight(
- fontSize: 18,
- fontWeight: FontWeight.bold,
- color: Colors.white70,
- letterSpacing: 0.1,
- ),
- ),
- )
- else
- Transform.translate(
- offset: Offset(0, 0),
- child: Text(
- "Announcements loaded successfully",
+ "ANNOUNCEMENTS LOADED",
style: GoogleFonts.interTight(
fontSize: 18,
fontWeight: FontWeight.bold,
@@ -303,10 +348,9 @@ class _AnnouncementUploadState extends State {
),
),
)
+ ],
- ],
-
- ),
+ ),
SizedBox(
height: 8,
@@ -368,6 +412,23 @@ class _AnnouncementUploadState extends State {
),
),
+ if (kIsWeb)
+ SizedBox(
+ height: 8,
+ ),
+
+ if (kIsWeb)
+ Text(
+ "Announcements uploaded on web are not persistent, and will need to be re-uploaded each time the site is loaded.",
+ style: GoogleFonts.interTight(
+ fontSize: 12,
+ fontWeight: FontWeight.w400,
+ color: Colors.white70,
+ letterSpacing: 0.1,
+ height: 1
+ ),
+ ),
+
SizedBox(
height: 8,
),
@@ -407,6 +468,153 @@ class _AnnouncementUploadState extends State {
}
}
+class PermissionsSetup extends StatefulWidget {
+
+ @override
+ State createState() => _PermissionsSetupState();
+}
+
+class _PermissionsSetupState extends State {
+ List _hasPermissions = [];
+
+ bool get hasPermissions {
+ return !_hasPermissions.contains(false) && _hasPermissions.length > 0;
+ }
+
+ Future requestPermission() async {
+ _hasPermissions = [];
+
+ print("Requesting location permission");
+ if (!await Permission.location.isGranted){
+ PermissionStatus locationStatus = await Permission.location.request();
+ if (locationStatus.isGranted) {
+ _hasPermissions.add(true);
+ LiveInformation().initTrackerModule();
+ } else {
+ _hasPermissions.add(false);
+ }
+ } else {
+ _hasPermissions.add(true);
+ }
+ print("Gotten result for location permission");
+
+ if (!kIsWeb){
+ print("Requesting storage permissions");
+ PermissionStatus fileStatus = await Permission.manageExternalStorage.request();
+
+ if (fileStatus.isGranted) {
+ _hasPermissions.add(true);
+ } else {
+ _hasPermissions.add(false);
+ }
+ } else {
+ _hasPermissions.add(true);
+ }
+
+ print("Permissions: $_hasPermissions");
+
+ setState(() {
+
+ });
+
+
+
+ }
+
+ @override
+ Widget build(BuildContext context) {
+
+ return Container(
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: Colors.white70,
+ width: 2
+ ),
+ ),
+
+ margin: EdgeInsets.symmetric(
+ horizontal: 8
+ ),
+ padding: EdgeInsets.all(8),
+
+ child: Column(
+
+ children: [
+
+ Row(
+
+ children: [
+
+ Icon(
+ hasPermissions ? Icons.check_box : Icons.error,
+ color: hasPermissions ? Colors.green : Colors.red,
+ size: 18,
+ ),
+
+ SizedBox(
+ width: 4,
+ ),
+
+ Transform.translate(
+ offset: Offset(0, 0),
+ child: Text(
+ hasPermissions ? "PERMISSIONS GRANTED" : "MISSING PERMISSIONS",
+ style: GoogleFonts.interTight(
+ fontSize: 18,
+ fontWeight: FontWeight.bold,
+ color: Colors.white70,
+ letterSpacing: 0.1,
+ ),
+ ),
+ ),
+
+
+
+ ],
+
+ ),
+
+ SizedBox(
+ height: 8,
+ ),
+
+ SizedBox(
+ height: 32,
+ width: double.infinity,
+ child: ElevatedButton(
+ onPressed: (){
+ requestPermission();
+ },
+
+ // make the corner radius 4, background color match the theme, and text colour white, fill to width of parent
+ style: ElevatedButton.styleFrom(
+ backgroundColor: Theme.of(context).colorScheme.primary,
+ foregroundColor: Colors.white,
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(4)
+ ),
+ ),
+
+ child: Text(
+ "Request permissions",
+ style: GoogleFonts.interTight(
+ fontSize: 15,
+ fontWeight: FontWeight.w600,
+ color: Colors.white,
+ letterSpacing: 0.5
+ )
+ )
+ ),
+ )
+
+ ],
+
+ ),
+
+ );
+ }
+}
+
enum _LoginType {
login,
signup
diff --git a/lib/pages/tfl_dataset_test.dart b/lib/pages/tfl_dataset_test.dart
index 556683b..0978a54 100644
--- a/lib/pages/tfl_dataset_test.dart
+++ b/lib/pages/tfl_dataset_test.dart
@@ -36,7 +36,7 @@ class TfL_Dataset_TestState extends State {
pages_Home(),
pages_Routes(),
pages_Display(this),
- pages_Settings(),
+ pages_Settings()
];
}
@@ -48,6 +48,11 @@ class TfL_Dataset_TestState extends State {
super.initState();
Future.delayed(Duration.zero, () async {
+
+ // if in debug mode skip all this
+ if (kDebugMode)
+ return;
+
try {
await LiveInformation().announcementModule.getBundleBytes();
} catch (e) {
@@ -90,80 +95,6 @@ class TfL_Dataset_TestState extends State {
return Scaffold(
-
- // appBar: !hideUI ? AppBar(
- //
- // surfaceTintColor: Colors.transparent,
- //
- // title: Container(
- //
- // child: Column(
- //
- // crossAxisAlignment: CrossAxisAlignment.start,
- //
- // children: [
- //
- // Text(
- // "Bus Infotainment",
- // style: GoogleFonts.teko(
- // fontSize: 25,
- // fontWeight: FontWeight.bold,
- // color: Colors.white,
- // height: 1,
- // ),
- // ),
- //
- // Row(
- //
- // children: [
- //
- // Text(
- // "Selected: ",
- // style: GoogleFonts.teko(
- // fontSize: 20,
- // fontWeight: FontWeight.w600,
- // color: Colors.white,
- // height: 1,
- // ),
- // ),
- //
- // if (liveInformation.getRouteVariant() != null)
- // Container(
- //
- // decoration: BoxDecoration(
- // color: Colors.black,
- // ),
- //
- // padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 2),
- //
- // child: Text(
- // "${liveInformation.getRouteVariant()!.busRoute.routeNumber} to ${liveInformation.getRouteVariant()!.busStops.last.formattedStopName}",
- // style: GoogleFonts.montserrat(
- // fontSize: 20,
- // fontWeight: FontWeight.w500,
- // color: Colors.orange.shade900,
- // ),
- // ),
- //
- // )
- // else
- // Text(
- // "None",
- // style: GoogleFonts.teko(
- // fontSize: 20,
- // fontWeight: FontWeight.w500,
- // color: Colors.white,
- // ),
- // ),
- // ],
- //
- // )
- //
- // ],
- //
- // ),
- // ),
- // ) : null,
body: Container(
width: double.infinity,
@@ -259,6 +190,55 @@ class TfL_Dataset_TestState extends State {
children: [
+ if (false)
+ Expanded(
+ child: Stack(
+ children: [
+ Container(
+ alignment: Alignment.center,
+ margin: const EdgeInsets.all(10),
+ child: Text(
+ "Dashboard",
+ style: GoogleFonts.teko(
+ color: Colors.white70,
+ fontSize: 20,
+ fontWeight: FontWeight.bold,
+ ),
+ )
+ ),
+ Positioned.fill(
+ child: ElevatedButton(
+ onPressed: () {
+ setState(() {
+ Navigator.pushNamed(context, "/dashboard");
+ });
+ },
+
+ style: ElevatedButton.styleFrom(
+ backgroundColor: Colors.transparent,
+ shadowColor: Colors.transparent,
+ surfaceTintColor: Colors.transparent,
+ foregroundColor: Colors.transparent,
+
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(0),
+ ),
+
+ ),
+
+ child: Container()
+ ),
+ )
+ ],
+ ),
+ ),
+
+ Container(
+ width: 2,
+ height: double.infinity,
+ color: Colors.white70,
+ ),
+
Expanded(
child: Stack(
children: [
diff --git a/lib/remaster/InitialStartup.dart b/lib/remaster/InitialStartup.dart
new file mode 100644
index 0000000..5282013
--- /dev/null
+++ b/lib/remaster/InitialStartup.dart
@@ -0,0 +1,465 @@
+
+
+import 'dart:io';
+
+import 'package:bus_infotainment/audio_cache.dart';
+import 'package:bus_infotainment/backend/live_information.dart';
+import 'package:file_picker/file_picker.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:google_fonts/google_fonts.dart';
+import 'package:permission_handler/permission_handler.dart';
+import 'package:shadcn_ui/shadcn_ui.dart';
+
+class InitialStartup extends StatefulWidget {
+
+ @override
+ State createState() => _InitialStartupState();
+}
+
+class _InitialStartupState extends State {
+ int _page = 0;
+
+ @override
+ Widget build(BuildContext context) {
+
+ if (_page == 0 && !kIsWeb) {
+ _page = 1;
+ }
+
+ return Scaffold(
+
+ body: [
+ _page1(this),
+ _page2(this),
+ _page3(this)
+ ][_page],
+
+ );
+
+ }
+
+ void setPage(int page) {
+ setState(() {
+ _page = page;
+ });
+ }
+}
+
+abstract class InitialStartupPage extends StatefulWidget {
+
+ _InitialStartupState parent;
+
+ InitialStartupPage(this.parent);
+
+}
+
+// Cookies page - only for web
+class _page1 extends InitialStartupPage {
+
+ _page1(super.parent);
+
+ @override
+ State<_page1> createState() => _page1State();
+}
+
+class _page1State extends State<_page1> {
+ @override
+ Widget build(BuildContext context) {
+ // TODO: implement build
+ return Container(
+
+ padding: EdgeInsets.all(32),
+
+ alignment: Alignment.center,
+
+ child: Column(
+
+ mainAxisSize: MainAxisSize.min,
+
+ children: [
+
+ Text(
+ "Cookies",
+ style: TextStyle(
+ fontSize: 32,
+ fontWeight: FontWeight.w600,
+ )
+ ),
+
+ Text(
+ "This website uses first-party cookies for the storage of user data. These cookies are necessary for the functioning of the site and help us provide you with a better browsing experience. By using this website, you consent to the use of these cookies.",
+ textAlign: TextAlign.center,
+ ),
+
+ SizedBox(
+ height: 8,
+ ),
+
+ ShadButton(
+ onPressed: () {
+ widget.parent.setPage(1);
+ },
+ text: Text(
+ "I understand and agree"
+ ),
+ )
+
+
+
+ ],
+
+ )
+
+ );
+ }
+}
+
+// Permission request page
+class _page2 extends InitialStartupPage {
+
+ _page2(super.parent);
+
+ @override
+ State<_page2> createState() => _page2State();
+}
+
+class _page2State extends State<_page2> {
+
+ Future _allPermissionsGranted() async {
+
+ List perms = [];
+
+ perms.addAll([
+ await Permission.manageExternalStorage.isGranted,
+ await Permission.location.isGranted
+ ]);
+
+ return !perms.contains(false);
+ }
+
+ @override
+ Widget build(BuildContext context) {
+
+ return Container(
+
+ padding: EdgeInsets.all(16),
+
+ alignment: Alignment.center,
+
+
+
+ child: SizedBox(
+
+ width: double.infinity,
+
+ child: Column(
+
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+
+ children: [
+
+ Text(
+ "Permissions",
+ style: TextStyle(
+ fontSize: 32,
+ fontWeight: FontWeight.w600,
+ )
+ ),
+
+ SizedBox(
+ height: 16,
+ ),
+
+ ShadCard(
+ width: double.infinity,
+ title: Text(
+ "Location",
+ ),
+ description: Text(
+ "Your location is required for automatically updating your nearest bus stop."
+ ),
+ content: Container(
+ child: Column(
+ children: [
+
+ SizedBox(
+ height: 4,
+ ),
+
+ FutureBuilder(
+ future: Permission.location.isGranted,
+ builder: (context, val) {
+ bool isEnabled = true;
+ String text = "Request permission";
+ Color color = Colors.white;
+
+ if (val.hasData) {
+ isEnabled = !val.data!;
+ }
+ if (!isEnabled) {
+ text = "Permission granted!";
+ color = Colors.green.shade400;
+ }
+
+ return ShadButton(
+ text: Text(text),
+ onPressed: () async {
+ await Permission.location.request();
+ setState(() {
+
+ });
+ },
+ enabled: isEnabled,
+ backgroundColor: color,
+ );
+ },
+ ),
+ ],
+ ),
+ ),
+ ),
+
+ SizedBox(
+ height: 16,
+ ),
+
+ ShadCard(
+ width: double.infinity,
+ title: Text(
+ "Storage",
+ ),
+ description: Text(
+ "Storage access is required to access recorded announcements."
+ ),
+ content: Container(
+ child: Column(
+ children: [
+
+ SizedBox(
+ height: 4,
+ ),
+
+ FutureBuilder(
+ future: Permission.manageExternalStorage.isGranted,
+ builder: (context, val) {
+ bool isEnabled = true;
+ String text = "Request permission";
+ Color color = Colors.white;
+
+ if (val.hasData) {
+ isEnabled = !val.data!;
+ }
+ if (!isEnabled) {
+ text = "Permission granted!";
+ color = Colors.green.shade400;
+ }
+
+ return ShadButton(
+ text: Text(text),
+ onPressed: () async {
+ await Permission.manageExternalStorage.request();
+ setState(() {
+
+ });
+ },
+ enabled: isEnabled,
+ backgroundColor: color,
+ );
+ },
+ )
+ ],
+ ),
+ ),
+ ),
+
+ SizedBox(
+ height: 16,
+ ),
+
+ FutureBuilder(
+ future: _allPermissionsGranted(),
+ builder: (context, val) {
+ bool isEnabled = true;
+ String text = "Continue";
+ Color color = Colors.white;
+
+ if (val.hasData) {
+ isEnabled = val.data!;
+ }
+ if (!isEnabled) {
+ text = "Grant all permissions before continuing";
+ }
+
+ return ShadButton(
+ text: Text(text),
+ onPressed: () async {
+ widget.parent.setPage(2);
+ },
+ enabled: isEnabled,
+ backgroundColor: color,
+ width: double.infinity,
+ );
+ },
+ )
+
+ ],
+ ),
+ )
+
+ );
+
+ }
+}
+
+class _page3 extends InitialStartupPage {
+ _page3(super.parent);
+
+ @override
+ State<_page3> createState() => _page3State();
+}
+
+class _page3State extends State<_page3> {
+
+ Future _announcementsUploaded() async {
+ try {
+ Uint8List bytes = await LiveInformation().announcementModule.getBundleBytes();
+ return true;
+ } catch (e) {
+ return false;
+ }
+
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ // TODO: implement build
+ return Container(
+
+ padding: EdgeInsets.all(16),
+
+ alignment: Alignment.center,
+
+ child: SizedBox(
+
+ width: double.infinity,
+
+ child: Column(
+
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+
+ children: [
+
+ Text(
+ "Prerequisites",
+ style: TextStyle(
+ fontSize: 32,
+ fontWeight: FontWeight.w600,
+ )
+ ),
+
+ SizedBox(
+ height: 16,
+ ),
+
+ ShadCard(
+ width: double.infinity,
+ title: Text(
+ "Announcement files",
+ ),
+ description: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ "You are required to upload the London iBus announcement files. These files can be acquire by submitting a request to TfL under the Freedom of Information Act (2000)"
+ ),
+ SizedBox(
+ height: 4,
+ ),
+ Text(
+ "Please upload a zip file."
+ )
+ ],
+ ),
+ content: Container(
+ child: Column(
+ children: [
+
+ SizedBox(
+ height: 4,
+ ),
+
+ FutureBuilder(
+ future: _announcementsUploaded(),
+ builder: (context, val) {
+ bool isEnabled = true;
+ String text = "Upload file";
+ Color color = Colors.white;
+
+ if (val.hasData) {
+ isEnabled = !val.data!;
+ }
+ if (!isEnabled) {
+ text = "File uploaded!";
+ color = Colors.green.shade400;
+ }
+
+ return ShadButton(
+ text: Text(text),
+ onPressed: () async {
+
+ FilePickerResult? result = await FilePicker.platform.pickFiles(
+ type: FileType.custom,
+ allowedExtensions: [
+ "zip"
+ ]
+ );
+
+ if (result != null) {
+ late Uint8List bytes;
+
+ if (kIsWeb) {
+ bytes = result.files.single.bytes!;
+ } else {
+ File file = File(result.files.single.path!);
+
+ bytes = file.readAsBytesSync();
+ }
+
+ LiveInformation().announcementModule.setBundleBytes(bytes);
+
+ AnnouncementCache cache = LiveInformation().announcementModule.announcementCache;
+
+ // load a random announcement to ensure that the file is usable
+ await cache.loadAnnouncementsFromBytes(bytes, ["S_WALTHAMSTOW_CENTRAL_001.mp3"]);
+
+ setState(() {
+
+ });
+
+ }
+
+
+ },
+ enabled: isEnabled,
+ backgroundColor: color,
+ );
+ },
+ )
+ ],
+ ),
+ ),
+ ),
+
+ ],
+
+ ),
+ )
+
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/remaster/RemasteredMain.dart b/lib/remaster/RemasteredMain.dart
new file mode 100644
index 0000000..6ef19bc
--- /dev/null
+++ b/lib/remaster/RemasteredMain.dart
@@ -0,0 +1,26 @@
+
+
+
+import 'package:bus_infotainment/remaster/InitialStartup.dart';
+import 'package:flutter/material.dart';
+import 'package:shadcn_ui/shadcn_ui.dart';
+
+class RemasteredApp extends StatelessWidget {
+
+ @override
+ Widget build(BuildContext context) {
+ // TODO: implement build
+ return ShadApp(
+ darkTheme: ShadThemeData(
+ brightness: Brightness.dark,
+ colorScheme: ShadSlateColorScheme.dark(),
+ ),
+
+ routes: {
+ '/': (context) => InitialStartup()
+ },
+
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/remaster/dashboard.dart b/lib/remaster/dashboard.dart
new file mode 100644
index 0000000..5d47c60
--- /dev/null
+++ b/lib/remaster/dashboard.dart
@@ -0,0 +1,365 @@
+
+import 'package:bus_infotainment/pages/components/ibus_display.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'dart:io' show Platform;
+
+import 'package:flutter/widgets.dart';
+import 'package:google_fonts/google_fonts.dart';
+import 'package:text_scroll/text_scroll.dart';
+
+Color rgb(int r, int g, int b) {
+ return Color.fromRGBO(r, g, b, 1);
+}
+
+class Dashboard extends StatelessWidget {
+
+ @override
+ Widget build(BuildContext context) {
+ // TODO: implement build
+ return Scaffold(
+
+ backgroundColor: Colors.grey.shade900,
+
+ bottomNavigationBar: ((defaultTargetPlatform == TargetPlatform.android || defaultTargetPlatform == TargetPlatform.iOS)) ? null : BottomAppBar(
+
+ color: Colors.grey.shade800,
+
+ child: Row(
+ children: [
+ IconButton(
+ icon: Icon(Icons.home),
+ onPressed: () {
+ Navigator.pushNamed(context, "/dashboard");
+ },
+ ),
+ IconButton(
+ icon: Icon(Icons.search),
+ onPressed: () {
+ Navigator.pushNamed(context, "/search");
+ },
+ ),
+ IconButton(
+ icon: Icon(Icons.settings),
+ onPressed: () {
+ Navigator.pushNamed(context, "/settings");
+ },
+ ),
+ ],
+ ),
+ ),
+
+ body: Column(
+ children: [
+
+ Container(
+
+ margin: EdgeInsets.all(16),
+ padding: EdgeInsets.all(8),
+
+ decoration: BoxDecoration(
+
+ borderRadius: BorderRadius.circular(10),
+
+ color: Colors.grey.shade800
+
+ ),
+
+ // height: 100,
+
+ child: ibus_display()
+ ),
+
+ Expanded(
+ child: Row(
+
+ children: [
+
+ if (false)
+ if (!(defaultTargetPlatform == TargetPlatform.android || defaultTargetPlatform == TargetPlatform.iOS))
+ NavigationRail(
+
+ selectedIndex: 0,
+
+ groupAlignment: 1,
+
+ destinations: [
+
+ NavigationRailDestination(
+ icon: Icon(Icons.home),
+ label: Text("Dashboard"),
+ ),
+
+ NavigationRailDestination(
+ icon: Icon(Icons.search),
+ label: Text("Routes")
+ ),
+
+ NavigationRailDestination(
+ icon: Icon(Icons.settings),
+ label: Text("Settings")
+ )
+
+ ],
+
+ ),
+
+ Expanded(
+ child: Container(
+
+ child: Column(
+
+ children: [
+
+ Container(
+
+ padding: EdgeInsets.symmetric(
+ horizontal: 16
+ ),
+
+ child: IntrinsicHeight(
+ child: Row(
+
+ children: [
+
+ Expanded(
+ child: Container(
+
+ decoration: BoxDecoration(
+
+ borderRadius: BorderRadius.circular(10),
+
+ color: Colors.grey.shade800
+
+ ),
+
+ padding: EdgeInsets.all(16),
+
+ child: IntrinsicWidth(
+ child: Column(
+
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.center,
+
+ children: [
+
+ Row(
+ mainAxisSize: MainAxisSize.max,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+
+ children: [
+ Text(
+ "Bus Route:",
+ style: GoogleFonts.interTight(
+ fontSize: 18,
+ fontWeight: FontWeight.bold,
+ color: Colors.white
+ )
+ ),
+
+ SizedBox(
+ width: 16,
+ ),
+
+ Text(
+ "11",
+ style: GoogleFonts.interTight(
+ fontSize: 18,
+ fontWeight: FontWeight.normal,
+ color: Colors.white
+ )
+ )
+ ],
+ ),
+ Row(
+ // mainAxisSize: MainAxisSize.min,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ "Destination:",
+ style: GoogleFonts.interTight(
+ fontSize: 18,
+ fontWeight: FontWeight.bold,
+ color: Colors.white
+ )
+ ),
+
+ const SizedBox(
+ width: 16,
+ ),
+
+ Text(
+ "Fullham Broadway",
+ style: GoogleFonts.interTight(
+ fontSize: 18,
+ fontWeight: FontWeight.normal,
+ color: Colors.white
+ )
+ )
+ ],
+ ),
+
+ const SizedBox(
+ height: 8,
+ ),
+
+ Row(
+ // mainAxisSize: MainAxisSize.min,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ "Next Stop:",
+ style: GoogleFonts.interTight(
+ fontSize: 18,
+ fontWeight: FontWeight.bold,
+ color: Colors.white
+ )
+ ),
+
+ const SizedBox(
+ width: 16,
+ ),
+
+ Text(
+ "St Thomas Hospital / County Hall",
+ style: GoogleFonts.interTight(
+ fontSize: 18,
+ fontWeight: FontWeight.normal,
+ color: Colors.white
+ ),
+ overflow: TextOverflow.fade,
+ )
+ ],
+ ),
+
+ Row(
+ // mainAxisSize: MainAxisSize.min,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Text(
+ "Last Stop:",
+ style: GoogleFonts.interTight(
+ fontSize: 18,
+ fontWeight: FontWeight.bold,
+ color: Colors.white
+ ),
+ overflow: TextOverflow.fade,
+ ),
+
+ const SizedBox(
+ width: 16,
+ ),
+
+ Text(
+ "Fullham Town Hall",
+ style: GoogleFonts.interTight(
+ fontSize: 18,
+ fontWeight: FontWeight.normal,
+ color: Colors.white
+ ),
+ overflow: TextOverflow.fade,
+ )
+ ],
+ ),
+
+
+
+ ],
+
+ ),
+ )
+
+ ),
+ ),
+
+ // SizedBox(
+ // width: 16,
+ // ),
+ //
+ // Column(
+ //
+ // children: [
+ //
+ // SizedBox(
+ //
+ // width: 150,
+ //
+ // child: FloatingActionButton(
+ // onPressed: () {
+ //
+ // },
+ //
+ // backgroundColor: Colors.red,
+ //
+ // child: Text(
+ // "Bus Stopping",
+ // style: GoogleFonts.interTight(
+ // fontSize: 18,
+ // fontWeight: FontWeight.bold,
+ // color: Colors.white
+ // )
+ //
+ // ),
+ // ),
+ // ),
+ //
+ // SizedBox(
+ // height: 16
+ // ),
+ //
+ // SizedBox(
+ //
+ // width: 150,
+ // height: 100,
+ //
+ // child: FloatingActionButton(
+ // onPressed: () {
+ //
+ // },
+ //
+ // backgroundColor: Colors.grey.shade600,
+ //
+ // child: Text(
+ // "Acknowledge Bus Stop",
+ // style: GoogleFonts.interTight(
+ // fontSize: 18,
+ // fontWeight: FontWeight.bold,
+ // color: Colors.white
+ // ),
+ // textAlign: TextAlign.center,
+ //
+ // ),
+ // ),
+ // )
+ //
+ // ],
+ //
+ // )
+
+ ],
+
+ ),
+ ),
+ )
+
+
+
+ ],
+
+ ),
+
+ ),
+ )
+
+ ],
+
+ ),
+ ),
+ ],
+ )
+
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/tfl_datasets.dart b/lib/tfl_datasets.dart
index 23eee8f..13a35c2 100644
--- a/lib/tfl_datasets.dart
+++ b/lib/tfl_datasets.dart
@@ -7,7 +7,7 @@ import 'package:bus_infotainment/backend/live_information.dart';
import 'package:bus_infotainment/backend/modules/info_module.dart';
import 'package:bus_infotainment/utils/NameBeautify.dart';
import 'package:bus_infotainment/utils/OrdinanceSurveyUtils.dart';
-import 'package:csv/csv.dart';
+import 'package:fast_csv/csv_converter.dart';
import 'package:vector_math/vector_math.dart';
class BusSequences extends InfoModule {
@@ -19,13 +19,16 @@ class BusSequences extends InfoModule {
BusSequences.fromCSV(String destinationsCSV, String busSequencesCSV) {
// Init the bus destinations
- List> destinationRows = const CsvToListConverter().convert(destinationsCSV);
+ List> destinationRows = CsvConverter().convert(destinationsCSV);
destinationRows.removeAt(0);
+ print("Destination rows: ${destinationRows.length}");
+
for (int i = 0; i < destinationRows.length; i++) {
try {
List entries = destinationRows[i];
+ // print("Parsing destination row $i: $entries");
String routeNumber = entries[0].toString();
@@ -50,9 +53,11 @@ class BusSequences extends InfoModule {
} catch (e) {}
}
+ print("Loaded ${destinations.length} destinations");
+
// Init the bus routes
- List> busSequenceRows = const CsvToListConverter().convert(busSequencesCSV);
+ List> busSequenceRows = CsvConverter().convert(busSequencesCSV);
busSequenceRows.removeAt(0);
for (int i = 0; i < busSequenceRows.length; i++) {
@@ -61,20 +66,21 @@ class BusSequences extends InfoModule {
{
List entries = busSequenceRows[i];
+ // print("Parsing bus sequence row $i: $entries");
String routeNumber = entries[0].toString();
BusRoute route = routes.containsKey(routeNumber) ? routes[routeNumber]! : BusRoute(routeNumber: routeNumber);
- int routeVariant = entries[1];
+ int routeVariant = int.parse(entries[1]);
BusRouteStop stop = BusRouteStop();
stop.stopName = entries[6].toString();
stop.stopCode = entries[4].toString();
- stop.easting = entries[7];
- stop.northing = entries[8];
- stop.heading = entries[9] != "" ? entries[9] : -1;
+ stop.easting = int.parse(entries[7]);
+ stop.northing = int.parse(entries[8]);
+ stop.heading = int.parse(entries[9] != "" ? entries[9] : "-1");
BusRouteVariant variant = route.routeVariants.containsKey(routeVariant) ? route.routeVariants[routeVariant]! : BusRouteVariant(routeVariant: routeVariant, busRoute: route);
@@ -90,6 +96,8 @@ class BusSequences extends InfoModule {
}
}
+ print("Loaded ${routes.length} routes");
+
}
}
@@ -164,6 +172,9 @@ class BusRouteVariant {
}
+ print("Nearest destination A: $nearestDestinationA, distance: $nearestDistanceA");
+ print("Nearest destination B: $nearestDestinationB, distance: $nearestDistanceB");
+
// Choose the nearest destination
if (nearestDistanceA < nearestDistanceB) {
_destination = nearestDestinationA;
@@ -172,8 +183,14 @@ class BusRouteVariant {
}
}
+
return _destination;
}
+
+ @override
+ String toString() {
+ return 'BusRouteVariant{routeVariant: $routeVariant, busRoute: ${busRoute.routeNumber}, busStops: ${busStops.length}, destinations: ${busRoute.destinations.length}}';
+ }
}
class BusRouteStop {
diff --git a/lib/utils/audio wrapper.dart b/lib/utils/audio wrapper.dart
index e4c0699..0dea43b 100644
--- a/lib/utils/audio wrapper.dart
+++ b/lib/utils/audio wrapper.dart
@@ -25,7 +25,7 @@ class AudioWrapper {
print("AudioWrapper mode: $mode");
- // mode = AudioWrapper_Mode.Mobile;
+ mode = AudioWrapper_Mode.Mobile;
}
justaudio.AudioSource _convertSource_JustAudio(AudioWrapperSource source){
@@ -126,11 +126,11 @@ class AudioWrapper {
} catch (e) {}
_justAudio_AudioPlayer = justaudio.AudioPlayer();
} else if (mode == AudioWrapper_Mode.Mobile) {
- _audioPlayer_AudioPlayer.stop();
+ // _audioPlayer_AudioPlayer.stop();
try {
- _audioPlayer_AudioPlayer.dispose();
+ // _audioPlayer_AudioPlayer.dispose();
} catch (e) {}
- _audioPlayer_AudioPlayer = audioplayers.AudioPlayer();
+ // _audioPlayer_AudioPlayer = audioplayers.AudioPlayer();
}
}
@@ -142,12 +142,13 @@ class AudioWrapper {
return AudioWrapper_State.NotPlaying;
}
} else {
- if (_audioPlayer_AudioPlayer.state == audioplayers.PlayerState.playing){
- return AudioWrapper_State.Playing;
- } else {
- return AudioWrapper_State.NotPlaying;
- }
+ // if (_audioPlayer_AudioPlayer.state == audioplayers.PlayerState.playing){
+ // return AudioWrapper_State.Playing;
+ // } else {
+ // return AudioWrapper_State.NotPlaying;
+ // }
}
+ return AudioWrapper_State.NotPlaying;
}
}
diff --git a/lib/utils/web_workarrounds.dart b/lib/utils/web_workarrounds.dart
new file mode 100644
index 0000000..faf340a
--- /dev/null
+++ b/lib/utils/web_workarrounds.dart
@@ -0,0 +1,15 @@
+
+import 'package:flutter/foundation.dart';
+
+String WW_AssetSource(String location) {
+ if (kIsWeb) {
+
+ // remove the first character if it is a '/'
+ if (location.startsWith('/')) {
+ location = location.substring(1);
+ }
+
+ return "assets/$location";
+ }
+ return location;
+}
\ No newline at end of file
diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift
index 58c12ea..22bd301 100644
--- a/macos/Flutter/GeneratedPluginRegistrant.swift
+++ b/macos/Flutter/GeneratedPluginRegistrant.swift
@@ -8,12 +8,12 @@ import Foundation
import audio_session
import audioplayers_darwin
import device_info_plus
-import flutter_tts
import flutter_web_auth_2
import geolocator_apple
import just_audio
import package_info_plus
import path_provider_foundation
+import rive_common
import screen_retriever
import shared_preferences_foundation
import url_launcher_macos
@@ -24,12 +24,12 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
- FlutterTtsPlugin.register(with: registry.registrar(forPlugin: "FlutterTtsPlugin"))
FlutterWebAuth2Plugin.register(with: registry.registrar(forPlugin: "FlutterWebAuth2Plugin"))
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
+ RivePlugin.register(with: registry.registrar(forPlugin: "RivePlugin"))
ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
diff --git a/pubspec.lock b/pubspec.lock
index d101904..a0272de 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -17,6 +17,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.4.10"
+ args:
+ dependency: transitive
+ description:
+ name: args
+ sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.5.0"
async:
dependency: transitive
description:
@@ -97,6 +105,14 @@ 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:
@@ -169,22 +185,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.0"
- csv:
- dependency: "direct main"
- description:
- name: csv
- sha256: c6aa2679b2a18cb57652920f674488d89712efaf4d3fdf2e537215b35fc19d6c
- url: "https://pub.dev"
- source: hosted
- version: "6.0.0"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
- sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
+ sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
url: "https://pub.dev"
source: hosted
- version: "1.0.6"
+ version: "1.0.8"
device_info_plus:
dependency: transitive
description:
@@ -209,6 +217,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.1"
+ fast_csv:
+ dependency: "direct main"
+ description:
+ name: fast_csv
+ sha256: "2165aa6b76daa0de168a712a157a78e60fd786257228935dd9d2809fe2ef7d8a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.2.11"
ffi:
dependency: transitive
description:
@@ -229,10 +245,10 @@ packages:
dependency: "direct main"
description:
name: file_picker
- sha256: d1d0ac3966b36dc3e66eeefb40280c17feb87fa2099c6e22e6a1fc959327bd03
+ sha256: b6283d7387310ad83bc4f3bc245b75d223a032ae6eba275afcd585de2b9a1476
url: "https://pub.dev"
source: hosted
- version: "8.0.0+1"
+ version: "8.0.1"
fixnum:
dependency: transitive
description:
@@ -246,6 +262,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
+ flutter_animate:
+ dependency: transitive
+ description:
+ name: flutter_animate
+ sha256: "7c8a6594a9252dad30cc2ef16e33270b6248c4dedc3b3d06c86c4f3f4dc05ae5"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.5.0"
flutter_lints:
dependency: "direct dev"
description:
@@ -254,6 +278,11 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.2"
+ flutter_localizations:
+ dependency: transitive
+ description: flutter
+ source: sdk
+ version: "0.0.0"
flutter_map:
dependency: "direct main"
description:
@@ -270,19 +299,27 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.19"
+ flutter_shaders:
+ dependency: transitive
+ description:
+ name: flutter_shaders
+ sha256: "02750b545c01ff4d8e9bbe8f27a7731aa3778402506c67daa1de7f5fc3f4befe"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.1.2"
+ flutter_svg:
+ dependency: transitive
+ description:
+ name: flutter_svg
+ sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.10+1"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
- flutter_tts:
- dependency: "direct main"
- description:
- name: flutter_tts
- sha256: aed2a00c48c43af043ed81145fd8503ddd793dafa7088ab137dbef81a703e53d
- url: "https://pub.dev"
- source: hosted
- version: "4.0.2"
flutter_web_auth_2:
dependency: transitive
description:
@@ -360,6 +397,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.2.1"
+ graphs:
+ dependency: transitive
+ description:
+ name: graphs
+ sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.1"
html:
dependency: transitive
description:
@@ -388,10 +433,10 @@ packages:
dependency: "direct main"
description:
name: intl
- sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
+ sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
url: "https://pub.dev"
source: hosted
- version: "0.19.0"
+ version: "0.18.1"
js:
dependency: transitive
description:
@@ -488,6 +533,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.2.0"
+ lucide_icons_flutter:
+ dependency: transitive
+ description:
+ name: lucide_icons_flutter
+ sha256: "43b11fa16f243529c538bcb4a1af014c03c177056c0d46039bc4f665320428c6"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.8"
matcher:
dependency: transitive
description:
@@ -520,6 +573,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.0"
+ modular_ui:
+ dependency: "direct main"
+ description:
+ name: modular_ui
+ sha256: c7bfa2d509f6b55f45833ea5a46c7b40030c2a3c8fb26f5211eab440235ee99f
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.0.5"
ntp:
dependency: "direct main"
description:
@@ -552,6 +613,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.0"
+ path_parsing:
+ dependency: transitive
+ description:
+ name: path_parsing
+ sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.1"
path_provider:
dependency: transitive
description:
@@ -648,6 +717,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.2.1"
+ petitparser:
+ dependency: transitive
+ description:
+ name: petitparser
+ sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.0.2"
platform:
dependency: transitive
description:
@@ -668,10 +745,10 @@ packages:
dependency: transitive
description:
name: pointycastle
- sha256: "70fe966348fe08c34bf929582f1d8247d9d9408130723206472b4687227e4333"
+ sha256: "79fbafed02cfdbe85ef3fd06c7f4bc2cbcba0177e61b765264853d4253b21744"
url: "https://pub.dev"
source: hosted
- version: "3.8.0"
+ version: "3.9.0"
polylabel:
dependency: transitive
description:
@@ -688,6 +765,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.0"
+ rive:
+ dependency: transitive
+ description:
+ name: rive
+ sha256: ec44b6cf7341e21727c4b0e762f4ac82f9a45f7e52df3ebad2d1289a726fbaaf
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.13.1"
+ rive_common:
+ dependency: transitive
+ description:
+ name: rive_common
+ sha256: "0f070bc0e764c570abd8b34d744ef30d1292bd4051f2e0951bbda755875fce6a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.3.3"
rxdart:
dependency: transitive
description:
@@ -704,6 +797,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.1.9"
+ shadcn_ui:
+ dependency: "direct main"
+ description:
+ name: shadcn_ui
+ sha256: "06c25555efbabe6d1d6acd6397bff4940e931d53ac3448e3a4f6a2287ab6798d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.3.3"
shared_preferences:
dependency: "direct main"
description:
@@ -837,6 +938,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.2.0"
+ two_dimensional_scrollables:
+ dependency: transitive
+ description:
+ name: two_dimensional_scrollables
+ sha256: c972f327282149a9018eb629ea848fdbc1acf6eda0969d86317c97ce8e4efa78
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.2.1"
typed_data:
dependency: transitive
description:
@@ -921,10 +1030,10 @@ packages:
dependency: transitive
description:
name: url_launcher_web
- sha256: "3692a459204a33e04bc94f5fb91158faf4f2c8903281ddd82915adecdb1a901d"
+ sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a"
url: "https://pub.dev"
source: hosted
- version: "2.3.0"
+ version: "2.3.1"
url_launcher_windows:
dependency: transitive
description:
@@ -941,6 +1050,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.4.0"
+ vector_graphics:
+ dependency: transitive
+ description:
+ name: vector_graphics
+ sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.11+1"
+ vector_graphics_codec:
+ dependency: transitive
+ description:
+ name: vector_graphics_codec
+ sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.11+1"
+ vector_graphics_compiler:
+ dependency: transitive
+ description:
+ name: vector_graphics_compiler
+ sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.11+1"
vector_math:
dependency: "direct main"
description:
@@ -985,10 +1118,10 @@ packages:
dependency: transitive
description:
name: win32_registry
- sha256: "41fd8a189940d8696b1b810efb9abcf60827b6cbfab90b0c43e8439e3a39d85a"
+ sha256: "10589e0d7f4e053f2c61023a31c9ce01146656a70b7b7f0828c0b46d7da2a9bb"
url: "https://pub.dev"
source: hosted
- version: "1.1.2"
+ version: "1.1.3"
window_manager:
dependency: "direct main"
description:
@@ -1021,6 +1154,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.4"
+ xml:
+ dependency: transitive
+ description:
+ name: xml
+ sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.5.0"
sdks:
dart: ">=3.3.0 <4.0.0"
flutter: ">=3.19.2"
diff --git a/pubspec.yaml b/pubspec.yaml
index f778d80..e0f0776 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -34,9 +34,9 @@ dependencies:
just_audio: ^0.9.36
just_audio_windows: ^0.2.0
audioplayers: ^6.0.0
- csv: ^6.0.0
+ fast_csv: ^0.2.11
http: ^1.2.1
- google_fonts: ^6.1.0
+ google_fonts: ^6.2.1
intl: any
text_scroll: ^0.2.0
flutter_map: ^6.1.0
@@ -49,8 +49,9 @@ dependencies:
geolocator: ^11.0.0
vector_math: ^2.1.4
permission_handler: ^11.3.0
- flutter_tts: ^4.0.2
file_picker: ^8.0.0+1
+ shadcn_ui: ^0.3.3
+ modular_ui: ^0.0.5
# The following adds the Cupertino Icons font to your application.
@@ -88,6 +89,7 @@ flutter:
- assets/audio/to_destination.wav
- assets/datasets/bus-blinds.csv
- assets/audio/5-seconds-of-silence.mp3
+ - assets/version.txt
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc
index 4ba1456..6461cbe 100644
--- a/windows/flutter/generated_plugin_registrant.cc
+++ b/windows/flutter/generated_plugin_registrant.cc
@@ -7,10 +7,10 @@
#include "generated_plugin_registrant.h"
#include
-#include
#include
#include
#include
+#include
#include
#include
#include
@@ -19,14 +19,14 @@
void RegisterPlugins(flutter::PluginRegistry* registry) {
AudioplayersWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
- FlutterTtsPluginRegisterWithRegistrar(
- registry->GetRegistrarForPlugin("FlutterTtsPlugin"));
GeolocatorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("GeolocatorWindows"));
JustAudioWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("JustAudioWindowsPlugin"));
PermissionHandlerWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
+ RivePluginRegisterWithRegistrar(
+ registry->GetRegistrarForPlugin("RivePlugin"));
ScreenRetrieverPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ScreenRetrieverPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(
diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake
index b8b98c6..f1afbb2 100644
--- a/windows/flutter/generated_plugins.cmake
+++ b/windows/flutter/generated_plugins.cmake
@@ -4,10 +4,10 @@
list(APPEND FLUTTER_PLUGIN_LIST
audioplayers_windows
- flutter_tts
geolocator_windows
just_audio_windows
permission_handler_windows
+ rive_common
screen_retriever
url_launcher_windows
window_manager