nice
This commit is contained in:
@@ -27,9 +27,7 @@ class AudioCache {
|
||||
|
||||
class AnnouncementCache extends AudioCache {
|
||||
|
||||
String _assetLocation = "assets/ibus_recordings.zip";
|
||||
|
||||
Future<void> loadAnnouncements(List<String> announcements) async {
|
||||
Future<void> loadAnnouncementsFromBytes(Uint8List bytes, List<String> announcements) async {
|
||||
|
||||
List<String> _announements = [];
|
||||
|
||||
@@ -45,7 +43,7 @@ class AnnouncementCache extends AudioCache {
|
||||
return;
|
||||
}
|
||||
|
||||
final bytes = await rootBundle.load(_assetLocation);
|
||||
// final bytes = await rootBundle.load(_assetLocation);
|
||||
final archive = ZipDecoder().decodeBytes(bytes.buffer.asUint8List());
|
||||
|
||||
for (final file in archive) {
|
||||
@@ -62,11 +60,11 @@ class AnnouncementCache extends AudioCache {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> loadAllAnnouncements() async {
|
||||
Future<void> loadAllAnnouncementsFromBytes(Uint8List bytes) async {
|
||||
|
||||
print("Loading all announcements.");
|
||||
|
||||
final bytes = await rootBundle.load(_assetLocation);
|
||||
// final bytes = await rootBundle.load(_assetLocation);
|
||||
final archive = ZipDecoder().decodeBytes(bytes.buffer.asUint8List());
|
||||
|
||||
print("Done decoding zip file.");
|
||||
@@ -88,5 +86,4 @@ class AnnouncementCache extends AudioCache {
|
||||
|
||||
print("Done loading all announcements.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -120,7 +120,7 @@ class AuthAPI extends ChangeNotifier {
|
||||
}) async {
|
||||
|
||||
try {
|
||||
final session = await account.createEmailSession(
|
||||
final session = await account.createEmailPasswordSession(
|
||||
email: email,
|
||||
password: password,
|
||||
);
|
||||
|
||||
@@ -68,11 +68,16 @@ class LiveInformation {
|
||||
announcementModule = AnnouncementModule();
|
||||
|
||||
// Tracker module is not supported on desktop
|
||||
if (defaultTargetPlatform != TargetPlatform.windows || defaultTargetPlatform != TargetPlatform.linux || defaultTargetPlatform != TargetPlatform.macOS) {
|
||||
if (defaultTargetPlatform != TargetPlatform.windows && defaultTargetPlatform != TargetPlatform.linux && defaultTargetPlatform != TargetPlatform.macOS) {
|
||||
// Tracker module is not supported on web
|
||||
await Permission.location.request();
|
||||
trackerModule = TrackerModule();
|
||||
Permission.location.request().then((value) {
|
||||
if (value.isGranted) {
|
||||
trackerModule = TrackerModule();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
print("Initialised LiveInformation");
|
||||
}
|
||||
|
||||
// Auth
|
||||
@@ -115,7 +120,7 @@ class LiveInformation {
|
||||
// Cache/Load the audio files
|
||||
await announcementModule
|
||||
.announcementCache
|
||||
.loadAnnouncements(audioFiles);
|
||||
.loadAnnouncementsFromBytes(await LiveInformation().announcementModule.getBundleBytes(), audioFiles);
|
||||
}
|
||||
|
||||
// Public methods
|
||||
|
||||
@@ -7,6 +7,8 @@ import 'package:bus_infotainment/backend/live_information.dart';
|
||||
import 'package:bus_infotainment/tfl_datasets.dart';
|
||||
import 'package:bus_infotainment/utils/audio%20wrapper.dart';
|
||||
import 'package:bus_infotainment/utils/delegates.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'info_module.dart';
|
||||
|
||||
@@ -19,6 +21,28 @@ class AnnouncementModule extends InfoModule {
|
||||
refreshTimer();
|
||||
}
|
||||
|
||||
// Files
|
||||
String _bundleLocation = "assets/ibus_recordings.zip";
|
||||
Uint8List? _bundleBytes;
|
||||
void setBundleBytes(Uint8List bytes) {
|
||||
_bundleBytes = bytes;
|
||||
}
|
||||
Future<Uint8List> getBundleBytes() async {
|
||||
|
||||
if (_bundleBytes != null) {
|
||||
return _bundleBytes!;
|
||||
} else {
|
||||
|
||||
if (kIsWeb) {
|
||||
throw Exception("Cannot load bundle bytes on web");
|
||||
}
|
||||
|
||||
final bytes = await rootBundle.load(_bundleLocation);
|
||||
return bytes.buffer.asUint8List();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Queue
|
||||
List<AnnouncementQueueEntry> queue = [];
|
||||
AnnouncementQueueEntry? currentAnnouncement;
|
||||
@@ -63,23 +87,34 @@ class AnnouncementModule extends InfoModule {
|
||||
onAnnouncement.trigger(currentAnnouncement!);
|
||||
|
||||
if (currentAnnouncement!.audioSources.isNotEmpty) {
|
||||
try {
|
||||
|
||||
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) {
|
||||
try {
|
||||
await audioPlayer.loadSource(source);
|
||||
|
||||
await audioPlayer.loadSource(source);
|
||||
|
||||
Duration? duration = await audioPlayer.play();
|
||||
await Future.delayed(duration!);
|
||||
if (currentAnnouncement?.audioSources.last != source) {
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
Duration? duration = await audioPlayer.play();
|
||||
await Future.delayed(duration!);
|
||||
if (currentAnnouncement?.audioSources.last != source) {
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
}
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
// print("Error playing announcement: $e on ${currentAnnouncement?.displayText}");
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
}
|
||||
}
|
||||
audioPlayer.stop();
|
||||
// audioPlayer.stop();
|
||||
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
print("Error playing announcement: $e");
|
||||
}
|
||||
// } catch (e) {
|
||||
// // Do nothing
|
||||
// print("Error playing announcement: $e on ${currentAnnouncement?.displayTex}");
|
||||
// }
|
||||
} else {
|
||||
if (queue.isNotEmpty) {
|
||||
await Future.delayed(const Duration(seconds: 5));
|
||||
@@ -153,7 +188,7 @@ class AnnouncementModule extends InfoModule {
|
||||
}
|
||||
|
||||
// Cache the announcements
|
||||
await announcementCache.loadAnnouncements(audioNames);
|
||||
await announcementCache.loadAnnouncementsFromBytes((await getBundleBytes())!, audioNames);
|
||||
|
||||
List<AudioWrapperSource> sources = [];
|
||||
|
||||
@@ -227,7 +262,7 @@ class AnnouncementModule extends InfoModule {
|
||||
|
||||
String audioRoute = "R_${routeVariant.busRoute.routeNumber}_001.mp3";
|
||||
|
||||
await announcementCache.loadAnnouncements([audioRoute, "R_RAIL_REPLACEMENT_SERVICE_001.mp3"]);
|
||||
await announcementCache.loadAnnouncementsFromBytes(await getBundleBytes(), [audioRoute, "R_RAIL_REPLACEMENT_SERVICE_001.mp3"]);
|
||||
|
||||
AudioWrapperSource sourceRoute = !routeNumber.toLowerCase().startsWith("ul") ?
|
||||
AudioWrapperByteSource(announcementCache[audioRoute]!) :
|
||||
|
||||
@@ -15,14 +15,17 @@ class SyncedTimeModule extends InfoModule {
|
||||
}
|
||||
|
||||
Timer refreshTimer() => Timer.periodic(const Duration(seconds: 10), (timer) async {
|
||||
var res = await http.get(Uri.parse('http://worldtimeapi.org/api/timezone/Europe/London'));
|
||||
if (res.statusCode == 200) {
|
||||
var json = jsonDecode(res.body);
|
||||
DateTime time = DateTime.parse(json['datetime']);
|
||||
timeOffset = time.millisecondsSinceEpoch - DateTime.now().millisecondsSinceEpoch;
|
||||
lastUpdate = DateTime.now();
|
||||
print("Time offset: $timeOffset");
|
||||
} else {
|
||||
|
||||
try {
|
||||
var res = await http.get(Uri.parse('http://worldtimeapi.org/api/timezone/Europe/London'));
|
||||
if (res.statusCode == 200) {
|
||||
var json = jsonDecode(res.body);
|
||||
DateTime time = DateTime.parse(json['datetime']);
|
||||
timeOffset = time.millisecondsSinceEpoch - DateTime.now().millisecondsSinceEpoch;
|
||||
lastUpdate = DateTime.now();
|
||||
print("Time offset: $timeOffset");
|
||||
}
|
||||
} catch (e) {
|
||||
print("Failed to get time from worldtimeapi.org");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -8,25 +8,29 @@ import 'package:bus_infotainment/backend/modules/info_module.dart';
|
||||
import 'package:bus_infotainment/tfl_datasets.dart';
|
||||
import 'package:bus_infotainment/utils/OrdinanceSurveyUtils.dart';
|
||||
import 'package:bus_infotainment/utils/audio%20wrapper.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:vector_math/vector_math.dart';
|
||||
|
||||
class TrackerModule extends InfoModule {
|
||||
|
||||
|
||||
// Constructor
|
||||
TrackerModule() {
|
||||
locationStream();
|
||||
Geolocator.getLastKnownPosition().then((Position? position) {
|
||||
this._position = position;
|
||||
updateNearestStop();
|
||||
});
|
||||
if (!kIsWeb)
|
||||
{
|
||||
Geolocator.getLastKnownPosition().then((Position? position) {
|
||||
this._position = position;
|
||||
updateNearestStop();
|
||||
});
|
||||
}
|
||||
liveInformation.routeVariantDelegate.addListener((routeVariant) {
|
||||
print("Route variant changed");
|
||||
updateNearestStop();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Location Tracker - will update the recorded location when the user moves.
|
||||
Position? _position;
|
||||
Position? get position => _position;
|
||||
|
||||
@@ -45,6 +49,7 @@ class TrackerModule extends InfoModule {
|
||||
updateNearestStop();
|
||||
});
|
||||
|
||||
// Location Refresher - will update the recorded location periodically.
|
||||
Timer refreshTimer() => Timer.periodic(Duration(seconds: 1), (timer) async {
|
||||
_position = await Geolocator.getCurrentPosition();
|
||||
});
|
||||
@@ -52,6 +57,7 @@ class TrackerModule extends InfoModule {
|
||||
BusRouteStop? nearestStop;
|
||||
bool hasArrived = false;
|
||||
|
||||
|
||||
Future<void> updateNearestStop() async {
|
||||
if (liveInformation.getRouteVariant() == null) {
|
||||
return;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
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:flutter/foundation.dart';
|
||||
@@ -26,9 +27,13 @@ void main() async {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
LiveInformation liveInformation = LiveInformation();
|
||||
await liveInformation.initialize();
|
||||
|
||||
runApp(const MyApp());
|
||||
|
||||
// Disalow screen to turn off on android
|
||||
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
|
||||
// Disalow landscape mode
|
||||
@@ -37,7 +42,7 @@ void main() async {
|
||||
DeviceOrientation.portraitDown,
|
||||
]);
|
||||
|
||||
runApp(const MyApp());
|
||||
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
@@ -71,7 +76,9 @@ class MyApp extends StatelessWidget {
|
||||
routes: {
|
||||
'/home': (context) => const MyHomePage(title: 'Flutter Demo Home Page'),
|
||||
'/audiocachetest': (context) => AudioCacheTest(),
|
||||
'/': (context) => TfL_Dataset_Test(),
|
||||
// '/': (context) => TfL_Dataset_Test(),
|
||||
'/': (context) => InitialStartup(),
|
||||
'/application': (context) => TfL_Dataset_Test(),
|
||||
|
||||
},
|
||||
);
|
||||
|
||||
@@ -27,7 +27,7 @@ class AudioCacheTest extends StatelessWidget {
|
||||
|
||||
body: Container(
|
||||
child: FutureBuilder(
|
||||
future: _announcementCache.loadAllAnnouncements(),
|
||||
future: Future.delayed(Duration(seconds: 1)), //todo
|
||||
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ class _ibus_displayState extends State<ibus_display> {
|
||||
width: 32*4*3,
|
||||
child: TextScroll(
|
||||
_padString(topLine),
|
||||
velocity: Velocity(pixelsPerSecond: Offset(120, 0)),
|
||||
velocity: Velocity(pixelsPerSecond: Offset(180, 0)),
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
color: Colors.orange,
|
||||
|
||||
@@ -248,27 +248,40 @@ class _SpeedometerState extends State<Speedometer> {
|
||||
|
||||
}
|
||||
|
||||
Timer? reloadTimer;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
// TODO: implement initState
|
||||
super.initState();
|
||||
|
||||
Timer.periodic(Duration(milliseconds: 250), (timer) {
|
||||
reloadTimer = Timer.periodic(Duration(milliseconds: 250), (timer) {
|
||||
|
||||
Position? newPosition = LiveInformation().trackerModule.position;
|
||||
try {
|
||||
Position? newPosition = LiveInformation().trackerModule.position;
|
||||
|
||||
speed = newPosition?.speed ?? 0;
|
||||
speed = newPosition?.speed ?? 0;
|
||||
|
||||
arrivalTime -= 0.25;
|
||||
arrivalTime = arrivalTime < 0 ? 0 : arrivalTime;
|
||||
arrivalTime -= 0.25;
|
||||
arrivalTime = arrivalTime < 0 ? 0 : arrivalTime;
|
||||
|
||||
setState(() {
|
||||
setState(() {
|
||||
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
// print(e);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
// TODO: implement dispose
|
||||
super.dispose();
|
||||
reloadTimer?.cancel();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// TODO: implement build
|
||||
|
||||
100
lib/pages/initial_startup.dart
Normal file
100
lib/pages/initial_startup.dart
Normal file
@@ -0,0 +1,100 @@
|
||||
|
||||
import 'package:bus_infotainment/pages/settings.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
class InitialStartup extends StatefulWidget {
|
||||
|
||||
@override
|
||||
State<InitialStartup> createState() => _InitialStartupState();
|
||||
}
|
||||
|
||||
const String Version = "0.2.0";
|
||||
|
||||
class _InitialStartupState extends State<InitialStartup> {
|
||||
bool AllowPassage = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// TODO: implement build
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
|
||||
alignment: Alignment.center,
|
||||
|
||||
child: Column(
|
||||
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
||||
children: [
|
||||
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
|
||||
AnnouncementUpload(
|
||||
onUploaded: () {
|
||||
AllowPassage = true;
|
||||
setState(() {
|
||||
|
||||
});
|
||||
},
|
||||
|
||||
),
|
||||
|
||||
if (AllowPassage)
|
||||
Container(
|
||||
|
||||
margin: EdgeInsets.all(8),
|
||||
|
||||
height: 32,
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: (){
|
||||
Navigator.pushNamed(context, "/application");
|
||||
},
|
||||
|
||||
// make the corner radius 4, background color match the theme, and text colour white, fill to width of parent
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.green,
|
||||
// foregroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(4)
|
||||
),
|
||||
),
|
||||
|
||||
child: Text(
|
||||
"Continue to application...",
|
||||
style: GoogleFonts.interTight(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
letterSpacing: 0.5
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
|
||||
Text(
|
||||
"Version $Version",
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.grey
|
||||
),
|
||||
)
|
||||
|
||||
],
|
||||
|
||||
|
||||
|
||||
)
|
||||
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:bus_infotainment/audio_cache.dart';
|
||||
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/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
@@ -71,20 +75,75 @@ class _pages_SettingsState extends State<pages_Settings> {
|
||||
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
|
||||
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
||||
children: [
|
||||
|
||||
|
||||
SizedBox(
|
||||
height: 8
|
||||
),
|
||||
|
||||
AnnouncementUpload(),
|
||||
|
||||
SizedBox(
|
||||
height: 8
|
||||
),
|
||||
|
||||
Container(
|
||||
margin: const EdgeInsets.all(8),
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: 8
|
||||
),
|
||||
child: SettingsField(
|
||||
label: "Announce distance",
|
||||
defaultValue: "150m",
|
||||
)
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: 8
|
||||
),
|
||||
|
||||
Container(
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: 8
|
||||
),
|
||||
child: SettingsField(
|
||||
label: "Announce time",
|
||||
defaultValue: "10s",
|
||||
)
|
||||
),
|
||||
|
||||
Container(
|
||||
|
||||
margin: EdgeInsets.only(
|
||||
left: 8,
|
||||
top: 2
|
||||
),
|
||||
|
||||
child: Text(
|
||||
"Console",
|
||||
style: GoogleFonts.teko(
|
||||
fontSize: 24
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Container(
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: 8
|
||||
),
|
||||
child: Console()
|
||||
),
|
||||
|
||||
if (false)
|
||||
Container(
|
||||
height: 2,
|
||||
width: double.infinity,
|
||||
color: Colors.white70,
|
||||
),
|
||||
|
||||
if (false)
|
||||
Container(
|
||||
|
||||
padding: const EdgeInsets.all(8),
|
||||
@@ -101,6 +160,253 @@ class _pages_SettingsState extends State<pages_Settings> {
|
||||
}
|
||||
}
|
||||
|
||||
class AnnouncementUpload extends StatefulWidget {
|
||||
|
||||
Function onUploaded = () {};
|
||||
|
||||
AnnouncementUpload({Key? key, this.onUploaded = _defaultOnUploaded}) : super(key: key);
|
||||
|
||||
static void _defaultOnUploaded() {}
|
||||
|
||||
@override
|
||||
State<AnnouncementUpload> createState() => _AnnouncementUploadState();
|
||||
}
|
||||
|
||||
class _AnnouncementUploadState extends State<AnnouncementUpload> {
|
||||
|
||||
Future<void> UploadButtonPressed() async {
|
||||
|
||||
// Pick the file
|
||||
FilePickerResult? result = await FilePicker.platform.pickFiles();
|
||||
|
||||
if (result != null) {
|
||||
print("Got file");
|
||||
|
||||
AnnouncementCache cache = LiveInformation().announcementModule.announcementCache;
|
||||
|
||||
LiveInformation().announcementModule.setBundleBytes(result.files[0].bytes!);
|
||||
|
||||
// load a random announcement to ensure that the file is usable
|
||||
await cache.loadAnnouncementsFromBytes(result.files[0].bytes!, ["S_WALTHAMSTOW_CENTRAL_001.mp3"]);
|
||||
|
||||
print("Loaded announcements");
|
||||
|
||||
setState(() {
|
||||
|
||||
});
|
||||
|
||||
widget.onUploaded();
|
||||
|
||||
} else {
|
||||
// User canceled the picker
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// TODO: implement build
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Colors.white70,
|
||||
width: 2
|
||||
),
|
||||
),
|
||||
|
||||
margin: EdgeInsets.symmetric(
|
||||
horizontal: 8
|
||||
),
|
||||
padding: EdgeInsets.all(8),
|
||||
|
||||
// height: 100,
|
||||
|
||||
child: Column(
|
||||
|
||||
children: [
|
||||
|
||||
Row(
|
||||
|
||||
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
|
||||
Icon(
|
||||
Icons.check,
|
||||
color: Colors.green,
|
||||
size: 18,
|
||||
),
|
||||
|
||||
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",
|
||||
style: GoogleFonts.interTight(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white70,
|
||||
letterSpacing: 0.1,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
],
|
||||
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
|
||||
Text(
|
||||
"Disclaimer: It is illegal to redistribute Transport for London's intellectual property. Even if it were permissible, the files are too large to be packaged into a website...",
|
||||
style: GoogleFonts.interTight(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.white70,
|
||||
letterSpacing: 0.1,
|
||||
height: 1
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
|
||||
Text(
|
||||
"...because of these reasons, you will have to provide the announcement files yourself.",
|
||||
style: GoogleFonts.interTight(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.white70,
|
||||
letterSpacing: 0.1,
|
||||
height: 1
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
|
||||
Text(
|
||||
"A ZIP file should be provided containg audio files with the correct naming scheme (e.g. S_WALTHAMSTOW_CENTRAL_001.mp3).",
|
||||
style: GoogleFonts.interTight(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.white70,
|
||||
letterSpacing: 0.1,
|
||||
height: 1
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
|
||||
Text(
|
||||
"No specific folder structure is required. The files will be sorted and indexed.",
|
||||
style: GoogleFonts.interTight(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.white70,
|
||||
letterSpacing: 0.1,
|
||||
height: 1
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: 32,
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: (){
|
||||
UploadButtonPressed();
|
||||
},
|
||||
|
||||
// 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(
|
||||
"Upload file",
|
||||
style: GoogleFonts.interTight(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
letterSpacing: 0.5
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum _LoginType {
|
||||
login,
|
||||
signup
|
||||
@@ -808,4 +1114,148 @@ class _ConsoleState extends State<Console> {
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SettingsField<T> extends StatelessWidget {
|
||||
|
||||
String label = "Untitled Field";
|
||||
|
||||
T defaultValue;
|
||||
|
||||
SettingsField({super.key, this.label = "Untitled Field", required this.defaultValue});
|
||||
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// TODO: implement build
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Colors.white70,
|
||||
width: 2
|
||||
),
|
||||
),
|
||||
|
||||
height: 50,
|
||||
|
||||
padding: EdgeInsets.all(4),
|
||||
|
||||
child: Row(
|
||||
|
||||
children: [
|
||||
|
||||
SizedBox(
|
||||
width: 4
|
||||
),
|
||||
|
||||
Text(
|
||||
label,
|
||||
style: GoogleFonts.teko(
|
||||
fontSize: 25,
|
||||
height: 1,
|
||||
letterSpacing: 0.02,
|
||||
color: Colors.white70
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
width: 8
|
||||
),
|
||||
|
||||
Expanded(
|
||||
child: Container(
|
||||
|
||||
height: double.infinity,
|
||||
|
||||
alignment: Alignment.center,
|
||||
|
||||
decoration: BoxDecoration(
|
||||
|
||||
border: Border.all(
|
||||
color: Colors.white70,
|
||||
width: 2
|
||||
)
|
||||
|
||||
),
|
||||
|
||||
child: Text(
|
||||
defaultValue.toString(),
|
||||
style: GoogleFonts.teko(
|
||||
fontSize: 25,
|
||||
height: 1
|
||||
)
|
||||
)
|
||||
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
width: 4
|
||||
),
|
||||
|
||||
AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
|
||||
height: double.infinity,
|
||||
width: double.infinity,
|
||||
|
||||
decoration: BoxDecoration(
|
||||
|
||||
border: Border.all(
|
||||
color: Colors.white70,
|
||||
width: 2
|
||||
)
|
||||
|
||||
),
|
||||
|
||||
child: Icon(
|
||||
Icons.edit,
|
||||
color: Colors.white70,
|
||||
size: 20,
|
||||
)
|
||||
|
||||
),
|
||||
|
||||
Container(
|
||||
|
||||
padding: EdgeInsets.all(2),
|
||||
|
||||
child: Positioned.fill(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
|
||||
},
|
||||
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
foregroundColor: Colors.transparent,
|
||||
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
),
|
||||
|
||||
),
|
||||
|
||||
child: Container()
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
],
|
||||
|
||||
)
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -42,6 +42,21 @@ class TfL_Dataset_TestState extends State<TfL_Dataset_Test> {
|
||||
|
||||
ibus_display _ibus_display = ibus_display();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
// TODO: implement initState
|
||||
super.initState();
|
||||
|
||||
Future.delayed(Duration.zero, () async {
|
||||
try {
|
||||
await LiveInformation().announcementModule.getBundleBytes();
|
||||
} catch (e) {
|
||||
Navigator.popAndPushNamed(context, "/");
|
||||
print("Sent back to initial startup");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
@@ -56,7 +71,7 @@ class TfL_Dataset_TestState extends State<TfL_Dataset_Test> {
|
||||
|
||||
if (defaultTargetPlatform == TargetPlatform.android) {
|
||||
shouldCurve = true;
|
||||
} else {
|
||||
} else if (defaultTargetPlatform == TargetPlatform.windows && !kIsWeb){
|
||||
rotated = _selectedIndex == 2;
|
||||
|
||||
print("Window size: ${MediaQuery.of(context).size}");
|
||||
@@ -156,295 +171,289 @@ class TfL_Dataset_TestState extends State<TfL_Dataset_Test> {
|
||||
|
||||
child: RotatedBox(
|
||||
quarterTurns: rotated ? 3 : 0,
|
||||
child: FittedBox(
|
||||
child: Container(
|
||||
|
||||
alignment: Alignment.topCenter,
|
||||
fit: BoxFit.fitWidth,
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 411.4,
|
||||
maxHeight: 850.3,
|
||||
),
|
||||
|
||||
child: Container(
|
||||
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 411.4,
|
||||
maxHeight: 850.3,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: shouldCurve ? const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(15),
|
||||
bottomRight: Radius.circular(15),
|
||||
) : null,
|
||||
border: Border.all(
|
||||
color: Colors.white70,
|
||||
width: 2,
|
||||
),
|
||||
color: Colors.grey.shade900,
|
||||
),
|
||||
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(6),
|
||||
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: shouldCurve ? const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(15),
|
||||
bottomRight: Radius.circular(15),
|
||||
) : null,
|
||||
border: Border.all(
|
||||
color: Colors.white70,
|
||||
width: 2,
|
||||
|
||||
child: Column(
|
||||
|
||||
children: [
|
||||
|
||||
if (!hideUI)
|
||||
Container(
|
||||
|
||||
margin: const EdgeInsets.all(6),
|
||||
|
||||
child: _ibus_display,
|
||||
),
|
||||
color: Colors.grey.shade900,
|
||||
),
|
||||
|
||||
margin: const EdgeInsets.all(6),
|
||||
if (!hideUI)
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 2,
|
||||
color: Colors.white70,
|
||||
),
|
||||
|
||||
Expanded(
|
||||
child: Container(
|
||||
|
||||
child: Column(
|
||||
margin: const EdgeInsets.all(8),
|
||||
|
||||
children: [
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Colors.white70,
|
||||
width: 2,
|
||||
),
|
||||
color: Colors.grey.shade900,
|
||||
borderRadius: hideUI && shouldCurve ? const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(7),
|
||||
bottomRight: Radius.circular(7),
|
||||
) : null,
|
||||
),
|
||||
|
||||
if (!hideUI)
|
||||
Container(
|
||||
child: ClipRRect(
|
||||
|
||||
margin: const EdgeInsets.all(6),
|
||||
|
||||
child: _ibus_display,
|
||||
),
|
||||
|
||||
if (!hideUI)
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 2,
|
||||
color: Colors.white70,
|
||||
),
|
||||
|
||||
Expanded(
|
||||
child: Container(
|
||||
|
||||
margin: const EdgeInsets.all(8),
|
||||
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
color: Colors.white70,
|
||||
width: 2,
|
||||
),
|
||||
color: Colors.grey.shade900,
|
||||
borderRadius: hideUI && shouldCurve ? const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(7),
|
||||
bottomRight: Radius.circular(7),
|
||||
) : null,
|
||||
// curved corners
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(7),
|
||||
bottomRight: Radius.circular(7),
|
||||
),
|
||||
|
||||
child: ClipRRect(
|
||||
|
||||
// curved corners
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(7),
|
||||
bottomRight: Radius.circular(7),
|
||||
),
|
||||
|
||||
child: Pages[_selectedIndex],
|
||||
)
|
||||
),
|
||||
child: Pages[_selectedIndex],
|
||||
)
|
||||
),
|
||||
),
|
||||
|
||||
if (!hideUI)
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 2,
|
||||
color: Colors.white70,
|
||||
),
|
||||
if (!hideUI)
|
||||
Container(
|
||||
width: double.infinity,
|
||||
height: 2,
|
||||
color: Colors.white70,
|
||||
),
|
||||
|
||||
if (!hideUI)
|
||||
Container(
|
||||
height: 50,
|
||||
if (!hideUI)
|
||||
Container(
|
||||
height: 50,
|
||||
|
||||
child: Row(
|
||||
child: Row(
|
||||
|
||||
children: [
|
||||
children: [
|
||||
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
margin: const EdgeInsets.all(10),
|
||||
child: Text(
|
||||
"Home",
|
||||
style: GoogleFonts.teko(
|
||||
color: Colors.white70,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
)
|
||||
),
|
||||
Positioned.fill(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 0;
|
||||
});
|
||||
},
|
||||
|
||||
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: [
|
||||
Container(
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
margin: const EdgeInsets.all(10),
|
||||
child: Text(
|
||||
"Routes",
|
||||
"Home",
|
||||
style: GoogleFonts.teko(
|
||||
color: Colors.white70,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
)
|
||||
),
|
||||
Positioned.fill(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 1;
|
||||
});
|
||||
},
|
||||
),
|
||||
Positioned.fill(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 0;
|
||||
});
|
||||
},
|
||||
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
foregroundColor: Colors.transparent,
|
||||
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
foregroundColor: Colors.transparent,
|
||||
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
),
|
||||
|
||||
child: Container()
|
||||
),
|
||||
|
||||
child: Container()
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Container(
|
||||
width: 2,
|
||||
height: double.infinity,
|
||||
color: Colors.white70,
|
||||
),
|
||||
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
margin: const EdgeInsets.all(10),
|
||||
child: Text(
|
||||
"Routes",
|
||||
style: GoogleFonts.teko(
|
||||
color: Colors.white70,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned.fill(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 1;
|
||||
});
|
||||
},
|
||||
|
||||
Container(
|
||||
width: 2,
|
||||
height: double.infinity,
|
||||
color: Colors.white70,
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
foregroundColor: Colors.transparent,
|
||||
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
margin: const EdgeInsets.all(10),
|
||||
child: Text(
|
||||
"Display",
|
||||
style: GoogleFonts.teko(
|
||||
color: Colors.white70,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
),
|
||||
)
|
||||
|
||||
),
|
||||
|
||||
child: Container()
|
||||
),
|
||||
Positioned.fill(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 2;
|
||||
});
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
foregroundColor: Colors.transparent,
|
||||
Container(
|
||||
width: 2,
|
||||
height: double.infinity,
|
||||
color: Colors.white70,
|
||||
),
|
||||
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
),
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
margin: const EdgeInsets.all(10),
|
||||
child: Text(
|
||||
"Display",
|
||||
style: GoogleFonts.teko(
|
||||
color: Colors.white70,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
)
|
||||
),
|
||||
Positioned.fill(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 2;
|
||||
});
|
||||
},
|
||||
|
||||
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: [
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
margin: const EdgeInsets.all(10),
|
||||
child: Text(
|
||||
"Settings",
|
||||
style: GoogleFonts.teko(
|
||||
color: Colors.white70,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
)
|
||||
child: Container()
|
||||
),
|
||||
Positioned.fill(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 3;
|
||||
});
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
foregroundColor: Colors.transparent,
|
||||
Container(
|
||||
width: 2,
|
||||
height: double.infinity,
|
||||
color: Colors.white70,
|
||||
),
|
||||
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
),
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
margin: const EdgeInsets.all(10),
|
||||
child: Text(
|
||||
"Settings",
|
||||
style: GoogleFonts.teko(
|
||||
color: Colors.white70,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
)
|
||||
),
|
||||
Positioned.fill(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedIndex = 3;
|
||||
});
|
||||
},
|
||||
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
foregroundColor: Colors.transparent,
|
||||
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(0),
|
||||
),
|
||||
|
||||
child: Container()
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
child: Container()
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
],
|
||||
],
|
||||
|
||||
),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
],
|
||||
],
|
||||
|
||||
)
|
||||
),
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -258,7 +258,7 @@ class BusDestination {
|
||||
print("Audio name B: $audioNameB");
|
||||
print("Audio name C: $audioNameC");
|
||||
|
||||
await LiveInformation().announcementModule.announcementCache.loadAnnouncements([audioNameA, audioNameB, audioNameC]);
|
||||
await LiveInformation().announcementModule.announcementCache.loadAnnouncementsFromBytes(await LiveInformation().announcementModule.getBundleBytes(), [audioNameA, audioNameB, audioNameC]);
|
||||
|
||||
Uint8List? audioBytesA = LiveInformation().announcementModule.announcementCache[audioNameA];
|
||||
Uint8List? audioBytesB = LiveInformation().announcementModule.announcementCache[audioNameB];
|
||||
|
||||
Reference in New Issue
Block a user