desktop push
This commit is contained in:
346
lib/remaster/SearchArc.dart
Normal file
346
lib/remaster/SearchArc.dart
Normal file
@@ -0,0 +1,346 @@
|
||||
|
||||
|
||||
import 'package:bus_infotainment/backend/live_information.dart';
|
||||
import 'package:bus_infotainment/remaster/dashboard.dart';
|
||||
import 'package:bus_infotainment/tfl_datasets.dart';
|
||||
import 'package:bus_infotainment/utils/OrdinanceSurveyUtils.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart' hide NavigationBar;
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
import 'package:vector_math/vector_math.dart' hide Colors;
|
||||
|
||||
import '../backend/modules/tube_info.dart';
|
||||
|
||||
class SearchArc extends StatefulWidget {
|
||||
|
||||
@override
|
||||
State<SearchArc> createState() => _SearchArcState();
|
||||
}
|
||||
|
||||
class _SearchArcState extends State<SearchArc> {
|
||||
TextEditingController searchController = TextEditingController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
List<Widget> nearbyRoutes = _getNearbyRoutes(context);
|
||||
List<Widget> pastRoutes = _getPastRoutes(context);
|
||||
|
||||
List<Widget> routeCards = [];
|
||||
|
||||
if (searchController.text.isNotEmpty) {
|
||||
// Detect if the search query is a route number
|
||||
// Examples of route numbers: 1, A1, 1A, A1A ...
|
||||
// If it isnt a route number, it is a stop name
|
||||
// Examples of stop names: "Euston Station", "Baker Street", "Kings Cross"
|
||||
bool containsNumber = RegExp(r'\d').hasMatch(searchController.text);
|
||||
|
||||
List<BusRoute> searchResults = [];
|
||||
|
||||
// Loop through all bus routes
|
||||
for (BusRoute route in LiveInformation().busSequences.routes.values) {
|
||||
if (containsNumber) {
|
||||
if (route.routeNumber.contains(searchController.text) && !searchResults.contains(route)) {
|
||||
routeCards.add(_getRouteCard(context, route));
|
||||
searchResults.add(route);
|
||||
}
|
||||
} else {
|
||||
for (BusRouteVariant variant in route.routeVariants.values) {
|
||||
for (BusRouteStop stop in variant.busStops) {
|
||||
if (stop.formattedStopName.toLowerCase().contains(
|
||||
searchController.text.toLowerCase()) && !searchResults.contains(route)) {
|
||||
routeCards.add(_getRouteCard(context, route));
|
||||
searchResults.add(route);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (routeCards.isEmpty){
|
||||
routeCards.add(
|
||||
Text("No results found", style: ShadTheme.of(context).textTheme.h3,)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
body: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.fromLTRB(32, 16, 32, 0),
|
||||
height: MediaQuery.of(context).size.height,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ShadInput(
|
||||
placeholder: Text("Search for route or stop (Can be laggy)"),
|
||||
controller: searchController,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
// Update search results
|
||||
});
|
||||
},
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
if (routeCards.isNotEmpty)
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Search results",
|
||||
style: ShadTheme.of(context).textTheme.h3,
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Expanded(
|
||||
child: GridView.extent(
|
||||
shrinkWrap: true,
|
||||
maxCrossAxisExtent: 100,
|
||||
scrollDirection: Axis.vertical,
|
||||
crossAxisSpacing: 8,
|
||||
mainAxisSpacing: 8,
|
||||
children: routeCards,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
else
|
||||
Expanded(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"Nearby routes",
|
||||
style: ShadTheme.of(context).textTheme.h3,
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Expanded(
|
||||
child: GridView.extent(
|
||||
shrinkWrap: true,
|
||||
maxCrossAxisExtent: 100,
|
||||
scrollDirection: Axis.vertical,
|
||||
crossAxisSpacing: 8,
|
||||
mainAxisSpacing: 8,
|
||||
children: _getNearbyRoutes(context, multiMode: true),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Container(
|
||||
width: 2,
|
||||
color: Colors.grey.shade300,
|
||||
),
|
||||
|
||||
RotatedBox(
|
||||
quarterTurns: 3,
|
||||
child: NavigationBar(),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
List<Widget> _getNearbyRoutes(context, {bool multiMode = false}) {
|
||||
|
||||
print("Getting nearby routes");
|
||||
|
||||
LiveInformation liveInformation = LiveInformation();
|
||||
BusSequences busSequences = liveInformation.busSequences;
|
||||
|
||||
List<BusRoute> nearbyRoutes = [];
|
||||
|
||||
Position? currentLocation = liveInformation.trackerModule.position;
|
||||
|
||||
Vector2 currentVector = Vector2(0, 0);
|
||||
|
||||
if (currentLocation == null && !kDebugMode) {
|
||||
return [];
|
||||
} else if (currentLocation != null){
|
||||
currentVector = OSGrid.toNorthingEasting(currentLocation!.latitude, currentLocation.longitude);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (kDebugMode) {
|
||||
currentVector = OSGrid.toNorthingEasting(51.583781262560926, -0.020359583104595073);
|
||||
}
|
||||
|
||||
for (BusRoute route in busSequences.routes.values) {
|
||||
for (BusRouteVariant variant in route.routeVariants.values) {
|
||||
for (BusRouteStop stop in variant.busStops) {
|
||||
|
||||
Vector2 stopVector = Vector2(stop.easting.toDouble(), stop.northing.toDouble());
|
||||
|
||||
double distance = currentVector.distanceTo(stopVector);
|
||||
|
||||
if (distance < 1000) {
|
||||
nearbyRoutes.add(route);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nearbyRoutes.contains(route)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nearbyRoutes.contains(route)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
List<Widget> routeCards = [];
|
||||
|
||||
for (BusRoute route in nearbyRoutes) {
|
||||
routeCards.add(_getRouteCard(context, route, multiMode: multiMode));
|
||||
}
|
||||
|
||||
return routeCards;
|
||||
|
||||
}
|
||||
|
||||
Widget _getRouteCard(context, BusRoute route, {bool multiMode = false}) {
|
||||
|
||||
String rr = "";
|
||||
|
||||
if (route.routeNumber.toLowerCase().startsWith("ul")) {
|
||||
|
||||
rr = "Rail replacement";
|
||||
|
||||
TubeLine? line = LiveInformation().tubeStations.getClosestLine(route.routeVariants.values.first);
|
||||
|
||||
rr = line?.name ?? rr;
|
||||
|
||||
if (!["London Overground", "DLR", "Rail replacement", "Elizabeth Line"].contains(rr)) {
|
||||
rr += " line";
|
||||
}
|
||||
if (rr == "Hammersmith and City line") {
|
||||
rr = "Hammersmith & City";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ElevatedButton(
|
||||
onPressed: () {
|
||||
showShadSheet(
|
||||
side: ShadSheetSide.right,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
|
||||
List<Widget> variantWidgets = [];
|
||||
|
||||
for (BusRouteVariant variant in route.routeVariants.values) {
|
||||
variantWidgets.add(
|
||||
ShadButton.outline(
|
||||
text: SizedBox(
|
||||
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text("${variant.busStops.first.formattedStopName} ->"),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
Text(variant.busStops.last.formattedStopName)
|
||||
],
|
||||
),
|
||||
),
|
||||
width: double.infinity,
|
||||
height: 50,
|
||||
padding: const EdgeInsets.all(8),
|
||||
onPressed: () async {
|
||||
LiveInformation liveInformation = LiveInformation();
|
||||
await liveInformation.setRouteVariant(variant);
|
||||
|
||||
if (!multiMode) {
|
||||
Navigator.popAndPushNamed(context, "/enroute");
|
||||
} else {
|
||||
Navigator.popAndPushNamed(context, "/multi/enroute");
|
||||
}
|
||||
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
variantWidgets.add(const SizedBox(
|
||||
height: 4,
|
||||
));
|
||||
}
|
||||
|
||||
return ShadSheet(
|
||||
title: Text("Route ${route.routeNumber} - Variants"),
|
||||
|
||||
content: Container(
|
||||
width: 300,
|
||||
height: MediaQuery.of(context).size.height - 52,
|
||||
child: Scrollbar(
|
||||
thumbVisibility: true,
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
...variantWidgets
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.all(8),
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
|
||||
Text(
|
||||
"Route \n ${route.routeNumber}",
|
||||
style: ShadTheme.of(context).textTheme.h4.copyWith(
|
||||
height: 1.1
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
if (route.routeNumber.toLowerCase().startsWith("ul"))
|
||||
Text(rr, style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w400, height: 1), textAlign: TextAlign.center,)
|
||||
|
||||
|
||||
],
|
||||
),
|
||||
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: EdgeInsets.all(10),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
);;
|
||||
}
|
||||
|
||||
List<Widget> _getPastRoutes(context) {
|
||||
return [];
|
||||
}
|
||||
Reference in New Issue
Block a user