shtuff
This commit is contained in:
@@ -1,365 +1,510 @@
|
||||
|
||||
import 'package:bus_infotainment/backend/live_information.dart';
|
||||
import 'package:bus_infotainment/pages/components/ibus_display.dart';
|
||||
import 'package:bus_infotainment/tfl_datasets.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:flutter_carousel_widget/flutter_carousel_widget.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import 'package:text_scroll/text_scroll.dart';
|
||||
|
||||
import '../backend/modules/tube_info.dart';
|
||||
|
||||
Color rgb(int r, int g, int b) {
|
||||
return Color.fromRGBO(r, g, b, 1);
|
||||
}
|
||||
|
||||
class Dashboard extends StatelessWidget {
|
||||
class HomePage_Re extends StatefulWidget {
|
||||
|
||||
@override
|
||||
State<HomePage_Re> createState() => _HomePage_ReState();
|
||||
}
|
||||
|
||||
class _HomePage_ReState extends State<HomePage_Re> {
|
||||
Future<bool> _shouldRedirectToSetup() async {
|
||||
|
||||
List<bool> perms = [];
|
||||
|
||||
perms.addAll([
|
||||
await Permission.manageExternalStorage.isGranted,
|
||||
await Permission.location.isGranted
|
||||
]);
|
||||
|
||||
bool shouldRedirectA = !perms.contains(false);
|
||||
bool shouldRedirectB = true;
|
||||
|
||||
try {
|
||||
Uint8List bytes = await LiveInformation().announcementModule.getBundleBytes();
|
||||
shouldRedirectB = true;
|
||||
} catch (e) {
|
||||
print("Failed to load bundle");
|
||||
shouldRedirectB = false;
|
||||
}
|
||||
|
||||
print("Should redirect to setup: ${shouldRedirectA || shouldRedirectB}");
|
||||
print("Permissions: $shouldRedirectA");
|
||||
print("Bundle: $shouldRedirectB");
|
||||
print("Permissions_indv: $perms");
|
||||
|
||||
return !shouldRedirectA || !shouldRedirectB;
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
|
||||
_shouldRedirectToSetup().then((value) {
|
||||
if (value) {
|
||||
Navigator.pushNamed(context, "/setup");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// TODO: implement build
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
|
||||
backgroundColor: Colors.grey.shade900,
|
||||
|
||||
bottomNavigationBar: ((defaultTargetPlatform == TargetPlatform.android || defaultTargetPlatform == TargetPlatform.iOS)) ? null : BottomAppBar(
|
||||
padding: EdgeInsets.all(16),
|
||||
|
||||
color: Colors.grey.shade800,
|
||||
alignment: Alignment.center,
|
||||
|
||||
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");
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: SizedBox(
|
||||
|
||||
body: Column(
|
||||
children: [
|
||||
width: double.infinity,
|
||||
|
||||
Container(
|
||||
child: Column(
|
||||
|
||||
margin: EdgeInsets.all(16),
|
||||
padding: EdgeInsets.all(8),
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
||||
decoration: BoxDecoration(
|
||||
children: [
|
||||
|
||||
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,
|
||||
//
|
||||
// ),
|
||||
// ),
|
||||
// )
|
||||
//
|
||||
// ],
|
||||
//
|
||||
// )
|
||||
|
||||
],
|
||||
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
||||
],
|
||||
|
||||
),
|
||||
|
||||
),
|
||||
Text(
|
||||
"Choose mode:",
|
||||
style: TextStyle(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.w600,
|
||||
)
|
||||
|
||||
],
|
||||
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
|
||||
ShadCard(
|
||||
title: Text("Solo mode"),
|
||||
width: double.infinity,
|
||||
description: Text(
|
||||
"Choose this mode if you are only using this device. (No internet required)"
|
||||
),
|
||||
content: Column(
|
||||
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
||||
children: [
|
||||
|
||||
SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
|
||||
ShadButton.secondary(
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(context, "/routes");
|
||||
},
|
||||
text: Text("Continue"),
|
||||
)
|
||||
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
|
||||
ShadCard(
|
||||
title: Text("Multi mode"),
|
||||
width: double.infinity,
|
||||
description: Text(
|
||||
"Choose this mode if you are using multiple devices. (Internet required)"
|
||||
),
|
||||
content: Column(
|
||||
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
||||
children: [
|
||||
|
||||
SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
|
||||
ShadButton.secondary(
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(context, "/application");
|
||||
},
|
||||
text: Text("Continue"),
|
||||
)
|
||||
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
],
|
||||
|
||||
),
|
||||
)
|
||||
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class RoutePage extends StatelessWidget {
|
||||
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
|
||||
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
|
||||
padding: EdgeInsets.all(16),
|
||||
|
||||
alignment: Alignment.center,
|
||||
|
||||
child: SizedBox(
|
||||
|
||||
width: double.infinity,
|
||||
|
||||
child: Column(
|
||||
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
||||
children: [
|
||||
|
||||
Text(
|
||||
"Routes",
|
||||
style: ShadTheme.of(context).textTheme.h1,
|
||||
),
|
||||
|
||||
Text(
|
||||
"Nearby routes",
|
||||
style: ShadTheme.of(context).textTheme.h4,
|
||||
),
|
||||
|
||||
ExpandableCarousel(
|
||||
options: CarouselOptions(
|
||||
|
||||
),
|
||||
items: [
|
||||
ShadCard(
|
||||
title: Text("Route 34"),
|
||||
content: ShadSelect(
|
||||
options: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text("Choose a variant"),
|
||||
)
|
||||
],
|
||||
selectedOptionBuilder: (BuildContext context, value) {
|
||||
return Text("Choose a variant");
|
||||
},
|
||||
),
|
||||
padding: EdgeInsets.all(10),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
||||
Divider(),
|
||||
|
||||
RouteSearch()
|
||||
|
||||
],
|
||||
|
||||
),
|
||||
)
|
||||
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
List<Widget> _getNearbyRoutes() {
|
||||
|
||||
final variants = [
|
||||
"Walthamstow Central to Barnet Church",
|
||||
"Walthamstow Central to Barnet Church",
|
||||
];
|
||||
|
||||
List<Widget> widgets = [];
|
||||
|
||||
for (int i = 0; i < variants.length; i++) {
|
||||
widgets.add(
|
||||
ShadOption(
|
||||
value: i,
|
||||
child: Text(variants[i]!),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return widgets;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class RouteSearch extends StatefulWidget {
|
||||
|
||||
@override
|
||||
State<RouteSearch> createState() => _RouteSearchState();
|
||||
}
|
||||
|
||||
class _RouteSearchState extends State<RouteSearch> {
|
||||
TextEditingController controller = TextEditingController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
List<Widget> routes = [];
|
||||
|
||||
for (BusRoute route in LiveInformation().busSequences.routes.values.toList()) {
|
||||
|
||||
if (controller.text.isNotEmpty && !route.routeNumber.toLowerCase().contains(controller.text.toLowerCase())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
routes.add(RouteCard(route: route));
|
||||
}
|
||||
|
||||
return Expanded(
|
||||
child: Column(
|
||||
|
||||
children: [
|
||||
|
||||
ShadInput(
|
||||
placeholder: Text("Search for a route..."),
|
||||
controller: controller,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
|
||||
});
|
||||
},
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
|
||||
Expanded(
|
||||
child: GridView.count(
|
||||
crossAxisCount: 3,
|
||||
children: [
|
||||
...routes
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
],
|
||||
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RouteCard extends StatelessWidget {
|
||||
|
||||
BusRoute route;
|
||||
|
||||
RouteCard({required this.route});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// TODO: implement build
|
||||
|
||||
Map<String, Widget> variants = {};
|
||||
|
||||
for (BusRouteVariant variant in route.routeVariants.values) {
|
||||
String variantLabel = "${variant.busStops.first.formattedStopName} -> ${variant.busStops.last.formattedStopName}";
|
||||
|
||||
variants[variantLabel] = ShadOption(
|
||||
value: variant.routeVariant.toString(),
|
||||
child: Text(variantLabel),
|
||||
);
|
||||
}
|
||||
|
||||
return AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: Container(
|
||||
child: ShadButton.secondary(
|
||||
text: Text(
|
||||
"Route \n ${route.routeNumber}",
|
||||
style: ShadTheme.of(context).textTheme.h3
|
||||
),
|
||||
padding: EdgeInsets.all(8),
|
||||
width: 105,
|
||||
height: 105,
|
||||
|
||||
onPressed: () {
|
||||
showShadSheet(
|
||||
side: ShadSheetSide.bottom,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
|
||||
List<Widget> variantWidgets = [];
|
||||
|
||||
for (BusRouteVariant variant in route.routeVariants.values) {
|
||||
String variantLabel = "${variant.busStops.first.formattedStopName} -> ${variant.busStops.last.formattedStopName}";
|
||||
|
||||
variantWidgets.add(
|
||||
ShadButton.outline(
|
||||
text: SizedBox(
|
||||
width: 800-490,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("${variant.busStops.first.formattedStopName} ->"),
|
||||
SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
Text(variant.busStops.last.formattedStopName)
|
||||
],
|
||||
),
|
||||
),
|
||||
width: double.infinity,
|
||||
height: 50,
|
||||
padding: EdgeInsets.all(8),
|
||||
onPressed: () async {
|
||||
LiveInformation liveInformation = LiveInformation();
|
||||
await liveInformation.setRouteVariant(variant);
|
||||
|
||||
liveInformation.announcementModule.queueAnnouncementByRouteVariant(routeVariant: variant);
|
||||
|
||||
Navigator.pushNamed(context, "/enroute");
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
variantWidgets.add(SizedBox(
|
||||
height: 4,
|
||||
));
|
||||
}
|
||||
|
||||
return ShadSheet(
|
||||
title: Text("Route ${route.routeNumber} - Variants"),
|
||||
|
||||
content: Container(
|
||||
width: 2000,
|
||||
alignment: Alignment.center,
|
||||
child: Column(
|
||||
children: [
|
||||
...variantWidgets
|
||||
],
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.all(8),
|
||||
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class EnRoutePage extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// TODO: implement build
|
||||
return Scaffold(
|
||||
body: Column(
|
||||
|
||||
children: [
|
||||
|
||||
Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
child: ibus_display()
|
||||
),
|
||||
|
||||
Divider(
|
||||
height: 1,
|
||||
),
|
||||
|
||||
ShadButton(
|
||||
text: Text("Route scanner"),
|
||||
onPressed: () {
|
||||
|
||||
LiveInformation liveInformation = LiveInformation();
|
||||
|
||||
TubeLine? line = liveInformation.tubeStations.getClosestLine(liveInformation.getRouteVariant()!);
|
||||
|
||||
ShadToaster.of(context).show(
|
||||
ShadToast(
|
||||
title: Text("Closest line"),
|
||||
description: Text(line == null ? "No line found" : line.name),
|
||||
duration: Duration(seconds: 5),
|
||||
)
|
||||
);
|
||||
|
||||
},
|
||||
),
|
||||
|
||||
ShadButton(
|
||||
text: Text("dest"),
|
||||
onPressed: () {
|
||||
LiveInformation liveInformation = LiveInformation();
|
||||
liveInformation.announcementModule.queueAnnouncementByRouteVariant(routeVariant: liveInformation.getRouteVariant()!);
|
||||
},
|
||||
)
|
||||
|
||||
],
|
||||
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
ShadSelectFormField<String>(
|
||||
options: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text("Choose a variant"),
|
||||
),
|
||||
...variants.values
|
||||
],
|
||||
selectedOptionBuilder: (context, value) => value ==
|
||||
'none'
|
||||
? const Text('Select a verified email to display')
|
||||
: Text(variants.keys.toList()[int.parse(value)-1]!),
|
||||
placeholder: Text("Choose a variant"),
|
||||
|
||||
),
|
||||
*/
|
||||
Reference in New Issue
Block a user