feat: proper routing
This commit is contained in:
parent
a6f9cfdaf4
commit
1211c9b16e
98
lib/components/EventLog.dart
Normal file
98
lib/components/EventLog.dart
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:uninav/nav/graph.dart';
|
||||||
|
import 'package:uninav/util/util.dart';
|
||||||
|
|
||||||
|
class EventLog extends StatefulWidget {
|
||||||
|
final List<GraphFeature> events;
|
||||||
|
|
||||||
|
const EventLog({Key? key, required this.events}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_EventLogState createState() => _EventLogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EventLogState extends State<EventLog> {
|
||||||
|
int _selectedIndex = -1;
|
||||||
|
|
||||||
|
void _onEventTapped(int index) {
|
||||||
|
setState(() {
|
||||||
|
_selectedIndex = index;
|
||||||
|
});
|
||||||
|
_scrollController.animateTo(
|
||||||
|
index * _itemExtent,
|
||||||
|
duration: const Duration(milliseconds: 500),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
static const double _itemExtent = 60.0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Theme(
|
||||||
|
data: ThemeData.light(),
|
||||||
|
child: SizedBox(
|
||||||
|
height: 200,
|
||||||
|
child: ListView.builder(
|
||||||
|
controller: _scrollController,
|
||||||
|
itemExtent: _itemExtent + 8.0,
|
||||||
|
itemCount: widget.events.length,
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
final event = widget.events[index];
|
||||||
|
final isActive = index >= _selectedIndex;
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () => _onEventTapped(index),
|
||||||
|
child: Container(
|
||||||
|
margin: const EdgeInsets.symmetric(vertical: 4.0),
|
||||||
|
padding: const EdgeInsets.all(4.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color:
|
||||||
|
isActive ? Colors.white : Colors.white.withOpacity(0.6),
|
||||||
|
borderRadius: BorderRadius.circular(8.0),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withOpacity(0.1),
|
||||||
|
blurRadius: 4.0,
|
||||||
|
offset: const Offset(0, 2),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(getIconForEvent(event)),
|
||||||
|
const SizedBox(width: 8.0),
|
||||||
|
Text(
|
||||||
|
getLabelForEvent(event),
|
||||||
|
style: TextStyle(color: Colors.black),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconData getIconForEvent(GraphFeature event) => event.when(
|
||||||
|
buildingFloor: (level, feature) => Icons.directions_walk,
|
||||||
|
portal: (fromFloor, from, toFloor, to, baseFeature) =>
|
||||||
|
baseFeature.type.maybeWhen(
|
||||||
|
door: (connects) => Icons.door_front_door,
|
||||||
|
stairs: (connects) => Icons.stairs,
|
||||||
|
lift: (connects_levels) => Icons.elevator,
|
||||||
|
orElse: () => Icons.question_mark,
|
||||||
|
),
|
||||||
|
basicFeature: (level, building, baseFeature) => Icons.location_on,
|
||||||
|
);
|
||||||
|
|
||||||
|
String getLabelForEvent(GraphFeature event) => event.when(
|
||||||
|
buildingFloor: (level, feature) => feature.name,
|
||||||
|
portal: (fromFloor, from, toFloor, to, baseFeature) =>
|
||||||
|
"$from:$fromFloor -> $to:$toFloor",
|
||||||
|
basicFeature: (level, building, baseFeature) =>
|
||||||
|
formatFeatureTitle(baseFeature),
|
||||||
|
);
|
@ -3,7 +3,9 @@ import 'package:flutter/widgets.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:uninav/components/colorful_chips.dart';
|
import 'package:uninav/components/colorful_chips.dart';
|
||||||
import 'package:uninav/controllers/map_controller.dart';
|
import 'package:uninav/controllers/map_controller.dart';
|
||||||
|
import 'package:uninav/controllers/navigation_controller.dart';
|
||||||
import 'package:uninav/data/geo/model.dart';
|
import 'package:uninav/data/geo/model.dart';
|
||||||
|
import 'package:uninav/nav/graph.dart';
|
||||||
import 'package:uninav/util/util.dart';
|
import 'package:uninav/util/util.dart';
|
||||||
|
|
||||||
final _colorfulBoxDeco = BoxDecoration(
|
final _colorfulBoxDeco = BoxDecoration(
|
||||||
@ -90,7 +92,39 @@ Future<void> showFeatureBottomSheet(
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
onPressed: () => {},
|
onPressed: () {
|
||||||
|
print("trying to start navigation...");
|
||||||
|
final navController = Get.find<NavigationController>();
|
||||||
|
final mapController = Get.find<MyMapController>();
|
||||||
|
|
||||||
|
// make feature into graphFeature
|
||||||
|
final wrapped = wrap(
|
||||||
|
feature,
|
||||||
|
mapController.currentLevel.value,
|
||||||
|
feature.buildingName ?? "")
|
||||||
|
.first;
|
||||||
|
|
||||||
|
print("1");
|
||||||
|
Get.back();
|
||||||
|
if (navController.position.value == null) {
|
||||||
|
print("2");
|
||||||
|
Get.snackbar(
|
||||||
|
"Navigation failed!",
|
||||||
|
"Please set your position first!",
|
||||||
|
snackPosition: SnackPosition.BOTTOM,
|
||||||
|
margin: const EdgeInsets.only(
|
||||||
|
bottom: 20, left: 10, right: 10),
|
||||||
|
colorText: Colors.white,
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
duration: const Duration(seconds: 3),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
print("3");
|
||||||
|
navController.navigate(navController.position.value!,
|
||||||
|
(feature) => feature.id == wrapped.id);
|
||||||
|
}
|
||||||
|
print("4");
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
34
lib/components/render_route.dart
Normal file
34
lib/components/render_route.dart
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:latlong2/latlong.dart';
|
||||||
|
import 'package:rust_core/iter.dart';
|
||||||
|
import 'package:uninav/controllers/navigation_controller.dart';
|
||||||
|
import 'package:uninav/nav/graph.dart';
|
||||||
|
|
||||||
|
class NavigationPathLayer extends StatelessWidget {
|
||||||
|
const NavigationPathLayer({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Obx(() {
|
||||||
|
// compute the polylines and markers
|
||||||
|
List<(GraphFeature, double)> route =
|
||||||
|
Get.find<NavigationController>().nav.iter().toList();
|
||||||
|
|
||||||
|
// distance-position pairs
|
||||||
|
// List<Polyline> polylines = [];
|
||||||
|
|
||||||
|
List<LatLng> polylinePoints =
|
||||||
|
route.map((e) => e.$1.getCenter().unwrap()).toList();
|
||||||
|
|
||||||
|
return PolylineLayer(polylines: [
|
||||||
|
Polyline(
|
||||||
|
points: polylinePoints,
|
||||||
|
strokeWidth: 4.0,
|
||||||
|
color: Colors.blue,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -41,6 +41,7 @@ class MyMapController extends GetxController {
|
|||||||
}
|
}
|
||||||
newLevels.sort();
|
newLevels.sort();
|
||||||
levels.value = newLevels;
|
levels.value = newLevels;
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> setLevel(int level) {
|
Result<void> setLevel(int level) {
|
||||||
@ -50,6 +51,7 @@ class MyMapController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
currentLevel.value = level;
|
currentLevel.value = level;
|
||||||
|
update();
|
||||||
return const Ok(());
|
return const Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,6 +113,7 @@ class MyMapController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
features.value = featuresList;
|
features.value = featuresList;
|
||||||
|
update();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error parsing GeoJSON: $e');
|
print('Error parsing GeoJSON: $e');
|
||||||
}
|
}
|
||||||
|
72
lib/controllers/navigation_controller.dart
Normal file
72
lib/controllers/navigation_controller.dart
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import 'package:anyhow/anyhow.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:rust_core/iter.dart';
|
||||||
|
import 'package:uninav/controllers/map_controller.dart';
|
||||||
|
import 'package:uninav/data/geo/model.dart';
|
||||||
|
import 'package:uninav/nav/graph.dart';
|
||||||
|
|
||||||
|
class NavigationController extends GetxController {
|
||||||
|
// Add controller logic and variables here
|
||||||
|
|
||||||
|
final RxList<(GraphFeature, double)> nav = RxList();
|
||||||
|
|
||||||
|
final Rx<GraphFeature?> position = Rx(null);
|
||||||
|
|
||||||
|
void navigate(
|
||||||
|
GraphFeature start, bool Function(GraphFeature) endSelector) async {
|
||||||
|
position.value = start;
|
||||||
|
|
||||||
|
final path = await compute(
|
||||||
|
(data) {
|
||||||
|
final start = data.$1;
|
||||||
|
final endSelector = data.$2;
|
||||||
|
final features = data.$3;
|
||||||
|
|
||||||
|
final path = findShortestPath(start, endSelector, features);
|
||||||
|
|
||||||
|
return path;
|
||||||
|
},
|
||||||
|
(
|
||||||
|
start,
|
||||||
|
endSelector,
|
||||||
|
Get.find<MyMapController>().features.iter().toList()
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (path.isErr()) {
|
||||||
|
Get.snackbar(
|
||||||
|
'Navigation Error',
|
||||||
|
'Unable to find a path to the destination\nMessage: ${path.unwrapErr().toString().split('\n')[0]}',
|
||||||
|
snackPosition: SnackPosition.BOTTOM,
|
||||||
|
margin: const EdgeInsets.only(bottom: 20, left: 10, right: 10),
|
||||||
|
colorText: Colors.white,
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
duration: const Duration(seconds: 3),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav.value = path.unwrap();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updatePosition(GraphFeature? newPosition) {
|
||||||
|
position.value = newPosition;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PathFindingData {
|
||||||
|
final GraphFeature start;
|
||||||
|
final bool Function(GraphFeature) endSelector;
|
||||||
|
final List<Feature> features;
|
||||||
|
|
||||||
|
_PathFindingData(this.start, this.endSelector, this.features);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<List<(GraphFeature, double)>> _findShortestPathIsolate(
|
||||||
|
_PathFindingData data) {
|
||||||
|
return findShortestPath(data.start, data.endSelector, data.features);
|
||||||
|
}
|
@ -92,6 +92,19 @@ class Feature with _$Feature {
|
|||||||
return bail("Feature Geometry is not a Polygon or Point");
|
return bail("Feature Geometry is not a Polygon or Point");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String? get buildingName => type.when(
|
||||||
|
building: () => name,
|
||||||
|
lectureHall: () => building,
|
||||||
|
room: (_) => building,
|
||||||
|
door: (_) => null,
|
||||||
|
toilet: (_) => building,
|
||||||
|
stairs: (_) => building,
|
||||||
|
lift: (_) => building,
|
||||||
|
foodDrink: () => building,
|
||||||
|
publicTransport: (_, __) => null,
|
||||||
|
pcPool: (_) => building,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:uninav/controllers/map_controller.dart';
|
import 'package:uninav/controllers/map_controller.dart';
|
||||||
|
import 'package:uninav/controllers/navigation_controller.dart';
|
||||||
import 'package:uninav/controllers/shared_prefs_controller.dart';
|
import 'package:uninav/controllers/shared_prefs_controller.dart';
|
||||||
import 'package:uninav/map.dart';
|
import 'package:uninav/map.dart';
|
||||||
import 'package:uninav/settings.dart';
|
import 'package:uninav/settings.dart';
|
||||||
@ -13,6 +14,8 @@ void main() {
|
|||||||
.loadString('assets/geo/uulm_beta.geojson')
|
.loadString('assets/geo/uulm_beta.geojson')
|
||||||
.then((value) => Get.find<MyMapController>().loadGeoJson(value));
|
.then((value) => Get.find<MyMapController>().loadGeoJson(value));
|
||||||
|
|
||||||
|
Get.put(NavigationController());
|
||||||
|
|
||||||
Get.putAsync(() async {
|
Get.putAsync(() async {
|
||||||
final controller = SharedPrefsController();
|
final controller = SharedPrefsController();
|
||||||
await controller.initialize();
|
await controller.initialize();
|
||||||
@ -43,7 +46,7 @@ class MyApp extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
initialRoute: '/map',
|
initialRoute: '/map',
|
||||||
getPages: [
|
getPages: [
|
||||||
GetPage(name: '/map', page: () => const MapPage()),
|
GetPage(name: '/map', page: () => MapPage()),
|
||||||
GetPage(name: '/settings', page: () => const SettingsPage()),
|
GetPage(name: '/settings', page: () => const SettingsPage()),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
136
lib/map.dart
136
lib/map.dart
@ -6,18 +6,45 @@ import 'package:flutter_map/flutter_map.dart';
|
|||||||
import 'package:flutter_map_location_marker/flutter_map_location_marker.dart';
|
import 'package:flutter_map_location_marker/flutter_map_location_marker.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
|
import 'package:rust_core/iter.dart';
|
||||||
import 'package:rust_core/slice.dart';
|
import 'package:rust_core/slice.dart';
|
||||||
|
import 'package:uninav/components/EventLog.dart';
|
||||||
import 'package:uninav/components/drawer.dart';
|
import 'package:uninav/components/drawer.dart';
|
||||||
import 'package:uninav/components/hamburger_menu.dart';
|
import 'package:uninav/components/hamburger_menu.dart';
|
||||||
import 'package:uninav/components/map_render_level.dart';
|
import 'package:uninav/components/map_render_level.dart';
|
||||||
|
import 'package:uninav/components/render_route.dart';
|
||||||
import 'package:uninav/controllers/map_controller.dart';
|
import 'package:uninav/controllers/map_controller.dart';
|
||||||
|
import 'package:uninav/controllers/navigation_controller.dart';
|
||||||
import 'package:uninav/data/geo/model.dart';
|
import 'package:uninav/data/geo/model.dart';
|
||||||
|
import 'package:uninav/nav/graph.dart';
|
||||||
import 'package:uninav/util/geojson_util.dart';
|
import 'package:uninav/util/geojson_util.dart';
|
||||||
import 'package:uninav/util/geomath.dart';
|
import 'package:uninav/util/geomath.dart';
|
||||||
|
import 'package:uninav/util/util.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
class MapPage extends StatelessWidget {
|
class MapPage extends StatefulWidget {
|
||||||
const MapPage({Key? key}) : super(key: key);
|
@override
|
||||||
|
State<MapPage> createState() => _MapPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MapPageState extends State<MapPage> {
|
||||||
|
late final Stream<LocationMarkerPosition?> _positionStream;
|
||||||
|
late final Stream<LocationMarkerHeading?> _headingStream;
|
||||||
|
|
||||||
|
/*
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
const factory = LocationMarkerDataStreamFactory();
|
||||||
|
_positionStream =
|
||||||
|
factory.fromGeolocatorPositionStream().asBroadcastStream();
|
||||||
|
_headingStream = factory.fromCompassHeadingStream().asBroadcastStream();
|
||||||
|
|
||||||
|
_geolocatorStream =
|
||||||
|
factory.defaultPositionStreamSource().asBroadcastStream();
|
||||||
|
_compassStream = factory.defaultHeadingStreamSource().asBroadcastStream();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -67,6 +94,13 @@ class MapPage extends StatelessWidget {
|
|||||||
TileLayer(
|
TileLayer(
|
||||||
urlTemplate: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
urlTemplate: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||||
maxZoom: 19,
|
maxZoom: 19,
|
||||||
|
tileBuilder: (context, tile, child) => ColorFiltered(
|
||||||
|
colorFilter: ColorFilter.mode(
|
||||||
|
Colors.white.withOpacity(0.7),
|
||||||
|
BlendMode.srcATop,
|
||||||
|
),
|
||||||
|
child: tile,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
TranslucentPointer(
|
TranslucentPointer(
|
||||||
child: LevelLayer(
|
child: LevelLayer(
|
||||||
@ -110,8 +144,26 @@ class MapPage extends StatelessWidget {
|
|||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
CurrentLocationLayer(),
|
CurrentLocationLayer(),
|
||||||
|
NavigationPathLayer(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
Positioned(
|
||||||
|
left: 16,
|
||||||
|
top: 16,
|
||||||
|
child: Container(
|
||||||
|
height: 450,
|
||||||
|
width: 150,
|
||||||
|
child: GetBuilder<NavigationController>(
|
||||||
|
builder: (controller) {
|
||||||
|
if (controller.nav.isNotEmpty) {
|
||||||
|
return EventLog(
|
||||||
|
events: controller.nav.map((e) => e.$1).toList());
|
||||||
|
} else {
|
||||||
|
return SizedBox();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)),
|
||||||
Positioned(
|
Positioned(
|
||||||
left: 16,
|
left: 16,
|
||||||
bottom: 16,
|
bottom: 16,
|
||||||
@ -233,8 +285,88 @@ void locationBottomSheet() {
|
|||||||
child: Container(
|
child: Container(
|
||||||
height: 300,
|
height: 300,
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'Level',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
GetBuilder<MyMapController>(
|
||||||
|
builder: (controller) {
|
||||||
|
return Wrap(
|
||||||
|
spacing: 8,
|
||||||
|
runSpacing: 8,
|
||||||
|
children: [
|
||||||
|
for (final level in controller.levels)
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () => controller.setLevel(level),
|
||||||
|
child: Chip(
|
||||||
|
label: Text("$level"),
|
||||||
|
backgroundColor:
|
||||||
|
controller.currentLevel == level
|
||||||
|
? Colors.blue
|
||||||
|
: Colors.grey[800],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Obx(() {
|
||||||
|
final navController =
|
||||||
|
Get.find<NavigationController>();
|
||||||
|
String? curBuilding;
|
||||||
|
if (navController.position.value
|
||||||
|
is BuildingFloor) {
|
||||||
|
curBuilding = (navController
|
||||||
|
.position.value as BuildingFloor)
|
||||||
|
.building
|
||||||
|
.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
final buildingList = controller.features
|
||||||
|
.where((f) => f.type is Building);
|
||||||
|
|
||||||
|
return Wrap(
|
||||||
|
spacing: 8,
|
||||||
|
runSpacing: 8,
|
||||||
|
children: [
|
||||||
|
for (final building in buildingList)
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
// print(building.name);
|
||||||
|
// print(curBuilding);
|
||||||
|
// print(navController.position);
|
||||||
|
navController.updatePosition(wrap(
|
||||||
|
building,
|
||||||
|
controller
|
||||||
|
.currentLevel.value,
|
||||||
|
building.name)
|
||||||
|
.firstOrNull);
|
||||||
|
},
|
||||||
|
child: Chip(
|
||||||
|
label: Text(building.name),
|
||||||
|
backgroundColor:
|
||||||
|
eq(curBuilding, building.name)
|
||||||
|
? building.level ==
|
||||||
|
controller
|
||||||
|
.currentLevel
|
||||||
|
? Colors.blue
|
||||||
|
: Colors.orange
|
||||||
|
: Colors.grey[800],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
})
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)),
|
||||||
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
child: StatefulBuilder(builder: (context, setState) {
|
child: StatefulBuilder(builder: (context, setState) {
|
||||||
|
@ -44,6 +44,19 @@ class GraphFeature with _$GraphFeature {
|
|||||||
basicFeature: (floor, building, feature) => feature.id,
|
basicFeature: (floor, building, feature) => feature.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// String? get buildingName => when(
|
||||||
|
// buildingFloor: (floor, building) => building.name,
|
||||||
|
// portal: (fromFloor, from, toFloor, to, baseFeature) =>
|
||||||
|
// baseFeature.type.maybeWhen(
|
||||||
|
// door: (_) => null,
|
||||||
|
// orElse: () => baseFeature.building,
|
||||||
|
// ),
|
||||||
|
// basicFeature: (floor, building, feature) => feature.type.maybeWhen(
|
||||||
|
// door: (_) => null,
|
||||||
|
// orElse: () => building,
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return when(
|
return when(
|
||||||
|
Loading…
Reference in New Issue
Block a user