feat: major progress
This commit is contained in:
parent
ba71707514
commit
be359980bb
30
.metadata
Normal file
30
.metadata
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# This file tracks properties of this Flutter project.
|
||||||
|
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||||
|
#
|
||||||
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
|
version:
|
||||||
|
revision: "54e66469a933b60ddf175f858f82eaeb97e48c8d"
|
||||||
|
channel: "stable"
|
||||||
|
|
||||||
|
project_type: app
|
||||||
|
|
||||||
|
# Tracks metadata for the flutter migrate command
|
||||||
|
migration:
|
||||||
|
platforms:
|
||||||
|
- platform: root
|
||||||
|
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
|
||||||
|
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
|
||||||
|
- platform: android
|
||||||
|
create_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
|
||||||
|
base_revision: 54e66469a933b60ddf175f858f82eaeb97e48c8d
|
||||||
|
|
||||||
|
# User provided section
|
||||||
|
|
||||||
|
# List of Local paths (relative to this file) that should be
|
||||||
|
# ignored by the migrate tool.
|
||||||
|
#
|
||||||
|
# Files that are not part of the templates will be ignored by default.
|
||||||
|
unmanaged_files:
|
||||||
|
- 'lib/main.dart'
|
||||||
|
- 'ios/Runner.xcodeproj/project.pbxproj'
|
16
README.md
16
README.md
@ -1,16 +1,8 @@
|
|||||||
# uninav
|
# uninav
|
||||||
|
|
||||||
A new Flutter project.
|
App to navigate in Universities. Developed at Uni Ulm, but made to be adaptable for all other universities, or complex indoor navigation environments
|
||||||
|
|
||||||
## Getting Started
|
## Building and such
|
||||||
|
|
||||||
This project is a starting point for a Flutter application.
|
run `flutter run` for running the app on your device.
|
||||||
|
run `dart run build_runner build` to run the code generator
|
||||||
A few resources to get you started if this is your first Flutter project:
|
|
||||||
|
|
||||||
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
|
||||||
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
|
||||||
|
|
||||||
For help getting started with Flutter development, view the
|
|
||||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
|
||||||
samples, guidance on mobile development, and a full API reference.
|
|
@ -26,3 +26,7 @@ linter:
|
|||||||
|
|
||||||
# Additional information about this file can be found at
|
# Additional information about this file can be found at
|
||||||
# https://dart.dev/guides/language/analysis-options
|
# https://dart.dev/guides/language/analysis-options
|
||||||
|
|
||||||
|
analyzer:
|
||||||
|
errors:
|
||||||
|
invalid_annotation_target: ignore
|
2070
assets/geo/uulm_beta.geojson
Normal file
2070
assets/geo/uulm_beta.geojson
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get_core/src/get_main.dart';
|
||||||
|
import 'package:get/get_navigation/get_navigation.dart';
|
||||||
|
import 'package:uninav/map.dart';
|
||||||
|
|
||||||
class MyDrawer extends StatelessWidget {
|
class MyDrawer extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
@ -20,9 +23,11 @@ class MyDrawer extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Icon(Icons.home),
|
leading: Icon(Icons.map),
|
||||||
title: Text('Home'),
|
title: Text('Map Page'),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
Get.back(); // close drawer
|
||||||
|
Get.toNamed('/map');
|
||||||
// Handle menu item tap
|
// Handle menu item tap
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -30,6 +35,8 @@ class MyDrawer extends StatelessWidget {
|
|||||||
leading: Icon(Icons.settings),
|
leading: Icon(Icons.settings),
|
||||||
title: Text('Settings'),
|
title: Text('Settings'),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
Get.back(); // close drawer
|
||||||
|
Get.toNamed('/settings');
|
||||||
// Handle menu item tap
|
// Handle menu item tap
|
||||||
},
|
},
|
||||||
),
|
),
|
17
lib/components/hamburger_menu.dart
Normal file
17
lib/components/hamburger_menu.dart
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class HamburgerMenu extends StatelessWidget {
|
||||||
|
const HamburgerMenu({
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return IconButton(
|
||||||
|
icon: Icon(Icons.menu),
|
||||||
|
onPressed: () {
|
||||||
|
Scaffold.of(context).openDrawer();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
256
lib/components/map_render_level.dart
Normal file
256
lib/components/map_render_level.dart
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:latlong2/latlong.dart';
|
||||||
|
import 'package:uninav/controllers/map_controller.dart';
|
||||||
|
import 'package:uninav/data/geo/model.dart';
|
||||||
|
import 'package:uninav/map.dart';
|
||||||
|
import 'package:uninav/util/geomath.dart';
|
||||||
|
|
||||||
|
List<Widget> renderLevel(int level) {
|
||||||
|
return <Widget>[
|
||||||
|
LevelLayer(
|
||||||
|
filter: (feature) =>
|
||||||
|
feature.level == level && feature.type is LectureHall,
|
||||||
|
polyConstructor: (feature) => feature
|
||||||
|
.getPolygon(
|
||||||
|
constructor: (pts) => Polygon(
|
||||||
|
points: pts,
|
||||||
|
color: Colors.orange.withOpacity(0.2),
|
||||||
|
borderColor: Colors.orange,
|
||||||
|
isFilled: true,
|
||||||
|
borderStrokeWidth: 1,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
markerConstructor: (feature) => Marker(
|
||||||
|
width: 150,
|
||||||
|
height: 60,
|
||||||
|
point: feature.getPoint().unwrap(),
|
||||||
|
builder: (cx) => Center(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.class_,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
Text('${feature.name}'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
LevelLayer(
|
||||||
|
filter: (feature) => feature.level == level && feature.type is Room,
|
||||||
|
polyConstructor: (feature) => feature
|
||||||
|
.getPolygon(
|
||||||
|
constructor: (pts) => Polygon(
|
||||||
|
points: pts,
|
||||||
|
color: Colors.green.withOpacity(0.2),
|
||||||
|
borderColor: Colors.green,
|
||||||
|
isFilled: true,
|
||||||
|
borderStrokeWidth: 1,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
LevelLayer(
|
||||||
|
filter: (feature) => feature.level == level && feature.type is Door,
|
||||||
|
markerConstructor: (feature) {
|
||||||
|
final point = feature.getPoint().unwrap();
|
||||||
|
return Marker(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
point: point,
|
||||||
|
builder: (ctx) => const Icon(
|
||||||
|
Icons.door_front_door,
|
||||||
|
color: Colors.brown,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
LevelLayer(
|
||||||
|
filter: (feature) => feature.level == level && feature.type is Toilet,
|
||||||
|
markerConstructor: (feature) {
|
||||||
|
final type = (feature.type as Toilet).toilet_type;
|
||||||
|
IconData icon;
|
||||||
|
switch (type.toLowerCase()) {
|
||||||
|
case 'male':
|
||||||
|
icon = Icons.male;
|
||||||
|
break;
|
||||||
|
case 'female':
|
||||||
|
icon = Icons.female;
|
||||||
|
break;
|
||||||
|
case 'handicap':
|
||||||
|
icon = Icons.wheelchair_pickup;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
print("WARN: Toilet didn't have recognizable type! "
|
||||||
|
"(Level ${feature.level}, Name ${feature.name}, "
|
||||||
|
"Location: ${feature.getPoint().unwrap()})");
|
||||||
|
icon = Icons.wc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
final point = feature.getPoint().unwrap();
|
||||||
|
return Marker(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
point: point,
|
||||||
|
builder: (ctx) => Icon(
|
||||||
|
icon,
|
||||||
|
color: Colors.purple,
|
||||||
|
),
|
||||||
|
rotateAlignment: Alignment.center,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
LevelLayer(
|
||||||
|
filter: (feature) =>
|
||||||
|
feature.type is Stairs &&
|
||||||
|
(feature.type as Stairs).connects_levels.contains(level),
|
||||||
|
markerConstructor: (feature) {
|
||||||
|
final point = feature.getPoint().unwrap();
|
||||||
|
return Marker(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
point: point,
|
||||||
|
builder: (ctx) => Icon(
|
||||||
|
Icons.stairs_outlined,
|
||||||
|
color: Colors.deepPurple.shade300,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
LevelLayer(
|
||||||
|
filter: (feature) =>
|
||||||
|
feature.type is Lift &&
|
||||||
|
(feature.type as Lift).connects_levels.contains(level),
|
||||||
|
markerConstructor: (feature) {
|
||||||
|
final point = feature.getPoint().unwrap();
|
||||||
|
return Marker(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
point: point,
|
||||||
|
builder: (ctx) => const Icon(
|
||||||
|
Icons.elevator_outlined,
|
||||||
|
color: Colors.deepPurple,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
class LevelLayer extends StatelessWidget {
|
||||||
|
final bool Function(Feature)? filter;
|
||||||
|
final Polygon Function(Feature)? polyConstructor;
|
||||||
|
final Marker Function(LatLng, String)? polyCenterMarkerConstructor;
|
||||||
|
final Marker Function(Feature)? markerConstructor;
|
||||||
|
final int? level;
|
||||||
|
|
||||||
|
const LevelLayer({
|
||||||
|
this.level,
|
||||||
|
this.filter,
|
||||||
|
this.polyConstructor,
|
||||||
|
this.polyCenterMarkerConstructor,
|
||||||
|
this.markerConstructor,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final myMapController = Get.find<MyMapController>();
|
||||||
|
|
||||||
|
return Obx(() {
|
||||||
|
final List<Polygon> filteredPolygons = [];
|
||||||
|
final List<Marker> polygonCenterMarkers = [];
|
||||||
|
final List<Marker> filteredMarkers = [];
|
||||||
|
|
||||||
|
for (final feature in myMapController.features) {
|
||||||
|
if (filter == null || filter!(feature)) {
|
||||||
|
if (feature.isPolygon()) {
|
||||||
|
if (polyConstructor != null) {
|
||||||
|
filteredPolygons.add(polyConstructor!(feature));
|
||||||
|
} else {
|
||||||
|
filteredPolygons.add(feature.getPolygon().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate polygon center
|
||||||
|
final center =
|
||||||
|
polygonCenterMinmax(feature.getPolygon().unwrap().points);
|
||||||
|
if (polyCenterMarkerConstructor != null) {
|
||||||
|
polygonCenterMarkers
|
||||||
|
.add(polyCenterMarkerConstructor!(center, feature.name));
|
||||||
|
} else {
|
||||||
|
polygonCenterMarkers.add(Marker(
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
point: center,
|
||||||
|
builder: (cx) => Center(
|
||||||
|
child: Text(
|
||||||
|
feature.name,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.black54,
|
||||||
|
// backgroundColor: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else if (feature.isPoint()) {
|
||||||
|
if (markerConstructor != null) {
|
||||||
|
filteredMarkers.add(markerConstructor!(feature));
|
||||||
|
} else {
|
||||||
|
final point = feature.getPoint().unwrap();
|
||||||
|
filteredMarkers.add(Marker(
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
point: point,
|
||||||
|
builder: (cx) => Center(
|
||||||
|
child: Text(
|
||||||
|
feature.name,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.black54,
|
||||||
|
// backgroundColor: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// print(filteredPolygons.length);
|
||||||
|
// print(filteredPolygons);
|
||||||
|
|
||||||
|
// print(filteredPolygons[0].points[0]);
|
||||||
|
// print(myMapController.features.length);
|
||||||
|
|
||||||
|
final List<Widget> widgets = [];
|
||||||
|
if (filteredPolygons.isNotEmpty) {
|
||||||
|
if (polyConstructor != null) {
|
||||||
|
widgets.add(PolygonLayer(polygons: filteredPolygons));
|
||||||
|
} else {
|
||||||
|
widgets.add(PolygonLayer(
|
||||||
|
polygons: filteredPolygons
|
||||||
|
.map((poly) => Polygon(
|
||||||
|
points: poly.points,
|
||||||
|
borderColor: Colors.black26,
|
||||||
|
borderStrokeWidth: 2.0,
|
||||||
|
))
|
||||||
|
.toList()));
|
||||||
|
}
|
||||||
|
widgets.add(MarkerLayer(
|
||||||
|
markers: polygonCenterMarkers,
|
||||||
|
rotate: true,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filteredMarkers.isNotEmpty) {
|
||||||
|
widgets.add(MarkerLayer(markers: filteredMarkers, rotate: true));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Stack(children: widgets);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
67
lib/controllers/map_controller.dart
Normal file
67
lib/controllers/map_controller.dart
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:anyhow/anyhow.dart';
|
||||||
|
import 'package:geojson/geojson.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:uninav/data/geo/model.dart';
|
||||||
|
import 'package:uninav/data/geo/parser.dart';
|
||||||
|
|
||||||
|
class MyMapController extends GetxController {
|
||||||
|
// constructor that calls loadgeojson with a default geojson string
|
||||||
|
final RxList<Feature> features = <Feature>[].obs;
|
||||||
|
final currentLevel = 1.obs;
|
||||||
|
final levels = <int>[1].obs;
|
||||||
|
@override
|
||||||
|
onInit() async {
|
||||||
|
print("init");
|
||||||
|
ever(features, refreshLevels);
|
||||||
|
super.onInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void refreshLevels(List<Feature> curFeatures) {
|
||||||
|
print("refreshLevels");
|
||||||
|
final newLevels = <int>[1];
|
||||||
|
for (final feature in curFeatures) {
|
||||||
|
if (feature.level != null && !newLevels.contains(feature.level)) {
|
||||||
|
newLevels.add(feature.level!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newLevels.sort();
|
||||||
|
levels.value = newLevels;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<void> setLevel(int level) {
|
||||||
|
// check that level is in features
|
||||||
|
if (!levels.contains(level)) {
|
||||||
|
return bail('Level $level is not in features');
|
||||||
|
}
|
||||||
|
|
||||||
|
currentLevel.value = level;
|
||||||
|
return const Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> loadGeoJson(String geoJsonString) async {
|
||||||
|
try {
|
||||||
|
// print(geoJsonString);
|
||||||
|
|
||||||
|
final featuresList = <Feature>[];
|
||||||
|
|
||||||
|
final geojson = GeoJson();
|
||||||
|
|
||||||
|
await geojson.parse(geoJsonString);
|
||||||
|
|
||||||
|
for (final feature in geojson.features) {
|
||||||
|
print(feature.properties);
|
||||||
|
final parsed =
|
||||||
|
parseFeature(feature.properties ?? <String, dynamic>{}, feature);
|
||||||
|
if (parsed case Ok(:final ok)) {
|
||||||
|
featuresList.add(ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
features.value = featuresList;
|
||||||
|
} catch (e) {
|
||||||
|
print('Error parsing GeoJSON: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
lib/data/geo/model.dart
Normal file
70
lib/data/geo/model.dart
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import 'package:anyhow/anyhow.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'package:geojson/geojson.dart';
|
||||||
|
import 'package:latlong2/latlong.dart';
|
||||||
|
|
||||||
|
part 'model.freezed.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class Feature with _$Feature {
|
||||||
|
const Feature._();
|
||||||
|
|
||||||
|
const factory Feature({
|
||||||
|
required String name,
|
||||||
|
required FeatureType type,
|
||||||
|
String? description,
|
||||||
|
required dynamic geometry,
|
||||||
|
int? level,
|
||||||
|
}) = _Feature;
|
||||||
|
|
||||||
|
bool isPolygon() {
|
||||||
|
return geometry is GeoJsonFeature<GeoJsonPolygon>;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPoint() {
|
||||||
|
return geometry is GeoJsonFeature<GeoJsonPoint>;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<Polygon> getPolygon({Polygon Function(List<LatLng>)? constructor}) {
|
||||||
|
if (isPolygon()) {
|
||||||
|
constructor ??= (pts) => Polygon(
|
||||||
|
points: pts, borderColor: Colors.black26, borderStrokeWidth: 2.0);
|
||||||
|
final polygon = geometry as GeoJsonFeature<GeoJsonPolygon>;
|
||||||
|
// print(polygon.geometry!.geoSeries[0].geoPoints);
|
||||||
|
final points = polygon.geometry!.geoSeries[0].geoPoints
|
||||||
|
.map((e) => LatLng(e.latitude, e.longitude))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
// print(points);
|
||||||
|
return Ok(constructor(points));
|
||||||
|
} else {
|
||||||
|
return bail("Feature Geometry is not a Polygon");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<LatLng> getPoint() {
|
||||||
|
if (isPoint()) {
|
||||||
|
final point = geometry as GeoJsonFeature<GeoJsonPoint>;
|
||||||
|
return Ok(LatLng(point.geometry!.geoPoint.latitude,
|
||||||
|
point.geometry!.geoPoint.longitude));
|
||||||
|
} else {
|
||||||
|
return bail("Feature Geometry is not a Point");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class FeatureType with _$FeatureType {
|
||||||
|
// multiple feature types like lecture hall, toliet, ...
|
||||||
|
const factory FeatureType.building() = Building;
|
||||||
|
const factory FeatureType.lectureHall() = LectureHall;
|
||||||
|
const factory FeatureType.room() = Room;
|
||||||
|
const factory FeatureType.door(List<String> connects) = Door;
|
||||||
|
const factory FeatureType.toilet(String toilet_type) = Toilet;
|
||||||
|
const factory FeatureType.stairs(List<int> connects_levels) = Stairs;
|
||||||
|
const factory FeatureType.lift(List<int> connects_levels) = Lift;
|
||||||
|
const factory FeatureType.publicTransport(
|
||||||
|
List<String> bus_lines, List<String> tram_lines) = PublicTransport;
|
||||||
|
}
|
1864
lib/data/geo/model.freezed.dart
Normal file
1864
lib/data/geo/model.freezed.dart
Normal file
File diff suppressed because it is too large
Load Diff
142
lib/data/geo/parser.dart
Normal file
142
lib/data/geo/parser.dart
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
import 'package:anyhow/anyhow.dart';
|
||||||
|
import 'package:geojson/geojson.dart';
|
||||||
|
import 'package:uninav/data/geo/model.dart';
|
||||||
|
import 'package:yaml/yaml.dart';
|
||||||
|
|
||||||
|
Result<Feature> parseFeature(
|
||||||
|
Map<String, dynamic> properties, dynamic geometry) {
|
||||||
|
final name = properties['name'] as String?;
|
||||||
|
final description_yaml = properties['description'] as String? ?? '';
|
||||||
|
final layer = properties['layer'] as String?;
|
||||||
|
|
||||||
|
int? level;
|
||||||
|
|
||||||
|
// check if layer key contains a digit using \d+ regex
|
||||||
|
|
||||||
|
final layerNum = RegExp(r'\d+').firstMatch(layer ?? '');
|
||||||
|
if (layerNum != null) {
|
||||||
|
level = int.parse(layerNum.group(0)!);
|
||||||
|
}
|
||||||
|
|
||||||
|
// try parse yaml
|
||||||
|
if (description_yaml == null) {
|
||||||
|
print("warn: Description key is missing for feature $name");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layer == null) {
|
||||||
|
return bail("Layer key \'layer\' is missing for feature $name");
|
||||||
|
}
|
||||||
|
dynamic yaml;
|
||||||
|
try {
|
||||||
|
yaml = loadYaml(description_yaml);
|
||||||
|
} on YamlException catch (e) {
|
||||||
|
return bail("Couldn't parse YAML in description for feature $name: $e");
|
||||||
|
}
|
||||||
|
|
||||||
|
yaml = yaml as YamlMap? ?? {};
|
||||||
|
final description = yaml['desription'] as String?;
|
||||||
|
|
||||||
|
print("yaml: $yaml");
|
||||||
|
|
||||||
|
var raw_type = yaml['type'] as String?;
|
||||||
|
if (raw_type == null && layer?.toLowerCase() == 'buildings') {
|
||||||
|
raw_type = 'building';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raw_type == null) {
|
||||||
|
return bail("Type key \'type\' is missing for feature $name");
|
||||||
|
}
|
||||||
|
|
||||||
|
FeatureType type;
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (raw_type) {
|
||||||
|
case 'building':
|
||||||
|
type = FeatureType.building();
|
||||||
|
case 'lift':
|
||||||
|
final list = getYamlList<int>(yaml, 'connects_levels')
|
||||||
|
.expect("Couldn't parse 'connects_levels' for feature $name");
|
||||||
|
type = FeatureType.lift(list);
|
||||||
|
break;
|
||||||
|
case 'stairs':
|
||||||
|
final list = getYamlList<int>(yaml, 'connects_levels')
|
||||||
|
.expect("Couldn't parse 'connects_levels' for feature $name");
|
||||||
|
type = FeatureType.stairs(list);
|
||||||
|
break;
|
||||||
|
case 'lecture_hall':
|
||||||
|
type = FeatureType.lectureHall();
|
||||||
|
break;
|
||||||
|
case 'room':
|
||||||
|
type = FeatureType.room();
|
||||||
|
break;
|
||||||
|
case 'door':
|
||||||
|
final list = getYamlList<String>(yaml, 'connects')
|
||||||
|
.expect("Couldn't parse 'connects' for feature $name");
|
||||||
|
type = FeatureType.door(list);
|
||||||
|
break;
|
||||||
|
case 'toilet':
|
||||||
|
final toiletType = getYamlKey<String>(yaml, 'toilet_type')
|
||||||
|
.expect("Couldn't parse 'toilet_type' for feature $name");
|
||||||
|
type = FeatureType.toilet(toiletType);
|
||||||
|
break;
|
||||||
|
case 'public_transport':
|
||||||
|
final busLines = getYamlList<dynamic>(yaml, 'bus_lines')
|
||||||
|
.expect("Couldn't parse 'bus_lines' for feature $name");
|
||||||
|
final tramLines = getYamlList<dynamic>(yaml, 'tram_lines')
|
||||||
|
.expect("Couldn't parse 'tram_lines' for feature $name");
|
||||||
|
|
||||||
|
type = FeatureType.publicTransport(
|
||||||
|
stringifyList(busLines)
|
||||||
|
.expect('Couldn\'t stringify \'bus_lines\' for feature $name'),
|
||||||
|
stringifyList(tramLines)
|
||||||
|
.expect('Couldn\'t stringify \'tram_lines\' for feature $name'),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return bail("Unknown feature type $raw_type for feature $name");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return bail("Failed to parse feature type for feature $name: $e");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(Feature(
|
||||||
|
name: name ?? 'Unknown',
|
||||||
|
type: type,
|
||||||
|
description: description,
|
||||||
|
geometry: geometry,
|
||||||
|
level: level,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<List<String>> stringifyList(List<dynamic> tramLines) {
|
||||||
|
try {
|
||||||
|
return Ok(tramLines.map((e) => e.toString()).toList());
|
||||||
|
} catch (e) {
|
||||||
|
return bail("Couldn't stringify list: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<List<T>> getYamlList<T>(YamlMap yaml, String key) {
|
||||||
|
try {
|
||||||
|
print('yaml is ${yaml[key]}');
|
||||||
|
final val = (yaml[key] as YamlList?);
|
||||||
|
if (val == null) {
|
||||||
|
return bail("Key $key is missing in yaml");
|
||||||
|
}
|
||||||
|
return Ok(val.cast<T>());
|
||||||
|
} catch (e) {
|
||||||
|
return bail("Failed to parse yaml key $key as ${T.toString()}: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<T> getYamlKey<T>(YamlMap yaml, String key) {
|
||||||
|
try {
|
||||||
|
final val = yaml[key] as T?;
|
||||||
|
if (val == null) {
|
||||||
|
return bail("Key $key is missing in yaml");
|
||||||
|
}
|
||||||
|
return Ok(val);
|
||||||
|
} catch (e) {
|
||||||
|
return bail("Failed to parse yaml key $key as ${T.toString()}: $e");
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get_navigation/src/root/get_material_app.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:uninav/controllers/map_controller.dart';
|
||||||
import 'package:uninav/map.dart';
|
import 'package:uninav/map.dart';
|
||||||
|
import 'package:uninav/settings.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
Get.put(MyMapController());
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,7 +36,11 @@ class MyApp extends StatelessWidget {
|
|||||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
),
|
),
|
||||||
home: MapPage(),
|
initialRoute: '/map',
|
||||||
|
getPages: [
|
||||||
|
GetPage(name: '/map', page: () => const MapPage()),
|
||||||
|
GetPage(name: '/settings', page: () => const SettingsPage()),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
387
lib/map.dart
387
lib/map.dart
@ -1,9 +1,16 @@
|
|||||||
import 'package:anim_search_bar/anim_search_bar.dart';
|
import 'package:anim_search_bar/anim_search_bar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_map/flutter_map.dart';
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
import 'package:flutter_map/plugin_api.dart';
|
import 'package:flutter_map/plugin_api.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
import 'package:uninav/components/drawer..dart';
|
import 'package:rust_core/slice.dart';
|
||||||
|
import 'package:uninav/components/drawer.dart';
|
||||||
|
import 'package:uninav/components/hamburger_menu.dart';
|
||||||
|
import 'package:uninav/controllers/map_controller.dart';
|
||||||
|
import 'package:uninav/data/geo/model.dart';
|
||||||
|
import 'package:uninav/util/geomath.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
class MapPage extends StatelessWidget {
|
class MapPage extends StatelessWidget {
|
||||||
@ -12,18 +19,10 @@ class MapPage extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
drawer: MyDrawer(),
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Map'),
|
title: const Text('Map'),
|
||||||
leading: Builder(
|
leading: HamburgerMenu(),
|
||||||
builder: (context) {
|
|
||||||
return IconButton(
|
|
||||||
icon: Icon(Icons.menu),
|
|
||||||
onPressed: () {
|
|
||||||
Scaffold.of(context).openDrawer();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
),
|
|
||||||
|
|
||||||
// right side expanding search bar widget
|
// right side expanding search bar widget
|
||||||
actions: [
|
actions: [
|
||||||
@ -39,29 +38,365 @@ class MapPage extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
drawer: MyDrawer(),
|
floatingActionButton: FloatingActionButton(
|
||||||
body: FlutterMap(
|
onPressed: () async {
|
||||||
|
// Add onPressed logic here
|
||||||
|
await Get.find<MyMapController>().loadGeoJson(
|
||||||
|
await rootBundle.loadString('assets/geo/uulm_beta.geojson'));
|
||||||
|
},
|
||||||
|
child: const Icon(Icons.add),
|
||||||
|
),
|
||||||
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
FlutterMap(
|
||||||
mapController: MapController(),
|
mapController: MapController(),
|
||||||
options: MapOptions(
|
options: MapOptions(
|
||||||
center: LatLng(51.5, -0.09),
|
center: LatLng(48.422766, 9.9564),
|
||||||
zoom: 13.0,
|
zoom: 16.0,
|
||||||
|
// camera constraints
|
||||||
|
maxZoom: 19,
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
TileLayer(
|
TileLayer(
|
||||||
urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
urlTemplate: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||||
subdomains: const ['a', 'b', 'c'],
|
maxZoom: 19,
|
||||||
|
),
|
||||||
|
|
||||||
|
// buildings
|
||||||
|
LevelLayer(
|
||||||
|
filter: (feature) => feature.type is Building,
|
||||||
|
),
|
||||||
|
|
||||||
|
// public transport
|
||||||
|
LevelLayer(
|
||||||
|
filter: (feature) =>
|
||||||
|
feature.level == null && feature.type is PublicTransport,
|
||||||
|
polyCenterMarkerConstructor: (center, name) => Marker(
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
point: center,
|
||||||
|
builder: (cx) => const Center(
|
||||||
|
child: Icon(
|
||||||
|
Icons.train,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
polyConstructor: (feature) => feature
|
||||||
|
.getPolygon(
|
||||||
|
constructor: (pts) => Polygon(
|
||||||
|
points: pts,
|
||||||
|
color: Colors.green.withOpacity(0.2),
|
||||||
|
borderColor: Colors.green,
|
||||||
|
isFilled: true,
|
||||||
|
borderStrokeWidth: 1,
|
||||||
|
))
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
|
||||||
|
// current level
|
||||||
|
Obx(
|
||||||
|
() => Stack(
|
||||||
|
children: renderLevel(
|
||||||
|
Get.find<MyMapController>().currentLevel.value),
|
||||||
),
|
),
|
||||||
RichAttributionWidget(attributions: [
|
|
||||||
TextSourceAttribution(
|
|
||||||
'OpenStreetMap contributors',
|
|
||||||
onTap: () =>
|
|
||||||
launchUrl(Uri.parse('https://openstreetmap.org/copyright')),
|
|
||||||
)
|
)
|
||||||
])
|
|
||||||
// PolygonLayer(polygons: myGeoJson.polygons),
|
// RichAttributionWidget(attributions: [
|
||||||
// PolylineLayer(polylines: myGeoJson.polylines),
|
// TextSourceAttribution(
|
||||||
// MarkerLayer(markers: myGeoJson.markers)
|
// 'OpenStreetMap contributors',
|
||||||
|
// onTap: () =>
|
||||||
|
// launchUrl(Uri.parse('https://openstreetmap.org/copyright')),
|
||||||
|
// )
|
||||||
|
// ]),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
left: 16,
|
||||||
|
bottom: 16,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.grey,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||||
|
child: Obx(
|
||||||
|
() => DropdownButton<int>(
|
||||||
|
value: Get.find<MyMapController>().currentLevel.value,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface),
|
||||||
|
dropdownColor: Theme.of(context).colorScheme.surface,
|
||||||
|
onChanged: (int? newValue) {
|
||||||
|
if (newValue != null) {
|
||||||
|
Get.find<MyMapController>().setLevel(newValue);
|
||||||
|
}
|
||||||
|
// Handle dropdown value change
|
||||||
|
},
|
||||||
|
items: Get.find<MyMapController>()
|
||||||
|
.levels
|
||||||
|
.map<DropdownMenuItem<int>>((int value) {
|
||||||
|
return DropdownMenuItem<int>(
|
||||||
|
value: value,
|
||||||
|
child: Text("Level $value"),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
],
|
],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Widget> renderLevel(int level) {
|
||||||
|
return <Widget>[
|
||||||
|
LevelLayer(
|
||||||
|
filter: (feature) =>
|
||||||
|
feature.level == level && feature.type is LectureHall,
|
||||||
|
polyConstructor: (feature) => feature
|
||||||
|
.getPolygon(
|
||||||
|
constructor: (pts) => Polygon(
|
||||||
|
points: pts,
|
||||||
|
color: Colors.orange.withOpacity(0.2),
|
||||||
|
borderColor: Colors.orange,
|
||||||
|
isFilled: true,
|
||||||
|
borderStrokeWidth: 1,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
markerConstructor: (feature) => Marker(
|
||||||
|
width: 150,
|
||||||
|
height: 60,
|
||||||
|
point: feature.getPoint().unwrap(),
|
||||||
|
builder: (cx) => Center(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.class_,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
Text('${feature.name}'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
LevelLayer(
|
||||||
|
filter: (feature) => feature.level == level && feature.type is Room,
|
||||||
|
polyConstructor: (feature) => feature
|
||||||
|
.getPolygon(
|
||||||
|
constructor: (pts) => Polygon(
|
||||||
|
points: pts,
|
||||||
|
color: Colors.green.withOpacity(0.2),
|
||||||
|
borderColor: Colors.green,
|
||||||
|
isFilled: true,
|
||||||
|
borderStrokeWidth: 1,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
LevelLayer(
|
||||||
|
filter: (feature) => feature.level == level && feature.type is Door,
|
||||||
|
markerConstructor: (feature) {
|
||||||
|
final point = feature.getPoint().unwrap();
|
||||||
|
return Marker(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
point: point,
|
||||||
|
builder: (ctx) => const Icon(
|
||||||
|
Icons.door_front_door,
|
||||||
|
color: Colors.brown,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
LevelLayer(
|
||||||
|
filter: (feature) => feature.level == level && feature.type is Toilet,
|
||||||
|
markerConstructor: (feature) {
|
||||||
|
final type = (feature.type as Toilet).toilet_type;
|
||||||
|
IconData icon;
|
||||||
|
switch (type.toLowerCase()) {
|
||||||
|
case 'male':
|
||||||
|
icon = Icons.male;
|
||||||
|
break;
|
||||||
|
case 'female':
|
||||||
|
icon = Icons.female;
|
||||||
|
break;
|
||||||
|
case 'handicap':
|
||||||
|
icon = Icons.wheelchair_pickup;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
print("WARN: Toilet didn't have recognizable type! "
|
||||||
|
"(Level ${feature.level}, Name ${feature.name}, "
|
||||||
|
"Location: ${feature.getPoint().unwrap()})");
|
||||||
|
icon = Icons.wc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
final point = feature.getPoint().unwrap();
|
||||||
|
return Marker(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
point: point,
|
||||||
|
builder: (ctx) => Icon(
|
||||||
|
icon,
|
||||||
|
color: Colors.purple,
|
||||||
|
),
|
||||||
|
rotateAlignment: Alignment.center,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
LevelLayer(
|
||||||
|
filter: (feature) =>
|
||||||
|
feature.type is Stairs &&
|
||||||
|
(feature.type as Stairs).connects_levels.contains(level),
|
||||||
|
markerConstructor: (feature) {
|
||||||
|
final point = feature.getPoint().unwrap();
|
||||||
|
return Marker(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
point: point,
|
||||||
|
builder: (ctx) => Icon(
|
||||||
|
Icons.stairs_outlined,
|
||||||
|
color: Colors.deepPurple.shade300,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
LevelLayer(
|
||||||
|
filter: (feature) =>
|
||||||
|
feature.type is Lift &&
|
||||||
|
(feature.type as Lift).connects_levels.contains(level),
|
||||||
|
markerConstructor: (feature) {
|
||||||
|
final point = feature.getPoint().unwrap();
|
||||||
|
return Marker(
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
point: point,
|
||||||
|
builder: (ctx) => const Icon(
|
||||||
|
Icons.elevator_outlined,
|
||||||
|
color: Colors.deepPurple,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
class LevelLayer extends StatelessWidget {
|
||||||
|
final bool Function(Feature)? filter;
|
||||||
|
final Polygon Function(Feature)? polyConstructor;
|
||||||
|
final Marker Function(LatLng, String)? polyCenterMarkerConstructor;
|
||||||
|
final Marker Function(Feature)? markerConstructor;
|
||||||
|
final int? level;
|
||||||
|
|
||||||
|
const LevelLayer({
|
||||||
|
this.level,
|
||||||
|
this.filter,
|
||||||
|
this.polyConstructor,
|
||||||
|
this.polyCenterMarkerConstructor,
|
||||||
|
this.markerConstructor,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final myMapController = Get.find<MyMapController>();
|
||||||
|
|
||||||
|
return Obx(() {
|
||||||
|
final List<Polygon> filteredPolygons = [];
|
||||||
|
final List<Marker> polygonCenterMarkers = [];
|
||||||
|
final List<Marker> filteredMarkers = [];
|
||||||
|
|
||||||
|
for (final feature in myMapController.features) {
|
||||||
|
if (filter == null || filter!(feature)) {
|
||||||
|
if (feature.isPolygon()) {
|
||||||
|
if (polyConstructor != null) {
|
||||||
|
filteredPolygons.add(polyConstructor!(feature));
|
||||||
|
} else {
|
||||||
|
filteredPolygons.add(feature.getPolygon().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate polygon center
|
||||||
|
final center =
|
||||||
|
polygonCenterMinmax(feature.getPolygon().unwrap().points);
|
||||||
|
if (polyCenterMarkerConstructor != null) {
|
||||||
|
polygonCenterMarkers
|
||||||
|
.add(polyCenterMarkerConstructor!(center, feature.name));
|
||||||
|
} else {
|
||||||
|
polygonCenterMarkers.add(Marker(
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
point: center,
|
||||||
|
builder: (cx) => Center(
|
||||||
|
child: Text(
|
||||||
|
feature.name,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.black54,
|
||||||
|
// backgroundColor: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else if (feature.isPoint()) {
|
||||||
|
if (markerConstructor != null) {
|
||||||
|
filteredMarkers.add(markerConstructor!(feature));
|
||||||
|
} else {
|
||||||
|
final point = feature.getPoint().unwrap();
|
||||||
|
filteredMarkers.add(Marker(
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
point: point,
|
||||||
|
builder: (cx) => Center(
|
||||||
|
child: Text(
|
||||||
|
feature.name,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.black54,
|
||||||
|
// backgroundColor: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// print(filteredPolygons.length);
|
||||||
|
// print(filteredPolygons);
|
||||||
|
|
||||||
|
// print(filteredPolygons[0].points[0]);
|
||||||
|
// print(myMapController.features.length);
|
||||||
|
|
||||||
|
final List<Widget> widgets = [];
|
||||||
|
if (filteredPolygons.isNotEmpty) {
|
||||||
|
if (polyConstructor != null) {
|
||||||
|
widgets.add(PolygonLayer(polygons: filteredPolygons));
|
||||||
|
} else {
|
||||||
|
widgets.add(PolygonLayer(
|
||||||
|
polygons: filteredPolygons
|
||||||
|
.map((poly) => Polygon(
|
||||||
|
points: poly.points,
|
||||||
|
borderColor: Colors.black26,
|
||||||
|
borderStrokeWidth: 2.0,
|
||||||
|
))
|
||||||
|
.toList()));
|
||||||
|
}
|
||||||
|
widgets.add(MarkerLayer(
|
||||||
|
markers: polygonCenterMarkers,
|
||||||
|
rotate: true,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filteredMarkers.isNotEmpty) {
|
||||||
|
widgets.add(MarkerLayer(markers: filteredMarkers, rotate: true));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Stack(children: widgets);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
21
lib/settings copy.dart
Normal file
21
lib/settings copy.dart
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:uninav/components/drawer.dart';
|
||||||
|
import 'package:uninav/components/hamburger_menu.dart';
|
||||||
|
|
||||||
|
class SettingsPage extends StatelessWidget {
|
||||||
|
const SettingsPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Settings'),
|
||||||
|
leading: HamburgerMenu(),
|
||||||
|
),
|
||||||
|
drawer: MyDrawer(),
|
||||||
|
body: const Center(
|
||||||
|
child: Text('TODO'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
21
lib/settings.dart
Normal file
21
lib/settings.dart
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:uninav/components/drawer.dart';
|
||||||
|
import 'package:uninav/components/hamburger_menu.dart';
|
||||||
|
|
||||||
|
class SettingsPage extends StatelessWidget {
|
||||||
|
const SettingsPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Settings'),
|
||||||
|
leading: HamburgerMenu(),
|
||||||
|
),
|
||||||
|
drawer: MyDrawer(),
|
||||||
|
body: const Center(
|
||||||
|
child: Text('TODO'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
37
lib/util/geomath.dart
Normal file
37
lib/util/geomath.dart
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:latlong2/latlong.dart';
|
||||||
|
|
||||||
|
LatLng polygonCenterMinmax(List<LatLng> polygon) {
|
||||||
|
double minLat = double.infinity;
|
||||||
|
double maxLat = double.negativeInfinity;
|
||||||
|
double minLng = double.infinity;
|
||||||
|
double maxLng = double.negativeInfinity;
|
||||||
|
|
||||||
|
for (LatLng point in polygon) {
|
||||||
|
minLat = min(minLat, point.latitude);
|
||||||
|
maxLat = max(maxLat, point.latitude);
|
||||||
|
minLng = min(minLng, point.longitude);
|
||||||
|
maxLng = max(maxLng, point.longitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
double centerLat = (minLat + maxLat) / 2;
|
||||||
|
double centerLng = (minLng + maxLng) / 2;
|
||||||
|
|
||||||
|
return LatLng(centerLat, centerLng);
|
||||||
|
}
|
||||||
|
|
||||||
|
LatLng polygonCenterAvg(List<LatLng> polygon) {
|
||||||
|
double sumLat = 0;
|
||||||
|
double sumLng = 0;
|
||||||
|
|
||||||
|
for (LatLng point in polygon) {
|
||||||
|
sumLat += point.latitude;
|
||||||
|
sumLng += point.longitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
double centerLat = sumLat / polygon.length;
|
||||||
|
double centerLng = sumLng / polygon.length;
|
||||||
|
|
||||||
|
return LatLng(centerLat, centerLng);
|
||||||
|
}
|
328
pubspec.lock
328
pubspec.lock
@ -1,6 +1,22 @@
|
|||||||
# Generated by pub
|
# Generated by pub
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
packages:
|
packages:
|
||||||
|
_fe_analyzer_shared:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: _fe_analyzer_shared
|
||||||
|
sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "67.0.0"
|
||||||
|
analyzer:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: analyzer
|
||||||
|
sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.4.1"
|
||||||
anim_search_bar:
|
anim_search_bar:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -9,6 +25,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.3"
|
version: "2.0.3"
|
||||||
|
anyhow:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: anyhow
|
||||||
|
sha256: "8fcd8a16ab1dadcae0d77b880c4cda85367876ef9da6ca7fd68ce6ce51679bbe"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.0"
|
||||||
|
args:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: args
|
||||||
|
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.0"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -25,6 +57,70 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.1"
|
||||||
|
build:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build
|
||||||
|
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
|
build_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_config
|
||||||
|
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
|
build_daemon:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_daemon
|
||||||
|
sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.1"
|
||||||
|
build_resolvers:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_resolvers
|
||||||
|
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.2"
|
||||||
|
build_runner:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: build_runner
|
||||||
|
sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.9"
|
||||||
|
build_runner_core:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_runner_core
|
||||||
|
sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.3.0"
|
||||||
|
built_collection:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: built_collection
|
||||||
|
sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.1.1"
|
||||||
|
built_value:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: built_value
|
||||||
|
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.9.2"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -33,6 +129,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.3.0"
|
||||||
|
checked_yaml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: checked_yaml
|
||||||
|
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.3"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -41,6 +145,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.1"
|
||||||
|
code_builder:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: code_builder
|
||||||
|
sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.10.0"
|
||||||
collection:
|
collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -49,6 +161,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.18.0"
|
version: "1.18.0"
|
||||||
|
convert:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: convert
|
||||||
|
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.1"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -65,6 +185,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.8"
|
version: "1.0.8"
|
||||||
|
dart_style:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dart_style
|
||||||
|
sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.6"
|
||||||
extra_pedantic:
|
extra_pedantic:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -81,6 +209,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.1"
|
version: "1.3.1"
|
||||||
|
file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file
|
||||||
|
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.0"
|
||||||
fixnum:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -120,6 +256,30 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
freezed:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: freezed
|
||||||
|
sha256: a434911f643466d78462625df76fd9eb13e57348ff43fe1f77bbe909522c67a1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.2"
|
||||||
|
freezed_annotation:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: freezed_annotation
|
||||||
|
sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
|
frontend_server_client:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: frontend_server_client
|
||||||
|
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.0"
|
||||||
geodesy:
|
geodesy:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -152,6 +312,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.6.6"
|
version: "4.6.6"
|
||||||
|
glob:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: glob
|
||||||
|
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
graphs:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: graphs
|
||||||
|
sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.1"
|
||||||
http:
|
http:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -160,6 +336,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.13.6"
|
version: "0.13.6"
|
||||||
|
http_multi_server:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_multi_server
|
||||||
|
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.1"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -176,6 +360,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.19.0"
|
version: "0.19.0"
|
||||||
|
io:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: io
|
||||||
|
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
iso:
|
iso:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -184,6 +376,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
|
js:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: js
|
||||||
|
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.1"
|
||||||
|
json_annotation:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: json_annotation
|
||||||
|
sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.8.1"
|
||||||
|
json_serializable:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: json_serializable
|
||||||
|
sha256: aa1f5a8912615733e0fdc7a02af03308933c93235bdc8d50d0b0c8a8ccb0b969
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.7.1"
|
||||||
latlong2:
|
latlong2:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -232,6 +448,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
|
logging:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: logging
|
||||||
|
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -264,6 +488,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.0"
|
||||||
|
mime:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: mime
|
||||||
|
sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.5"
|
||||||
|
package_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_config
|
||||||
|
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -296,6 +536,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
|
pool:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pool
|
||||||
|
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.5.1"
|
||||||
proj4dart:
|
proj4dart:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -304,6 +552,46 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.0"
|
||||||
|
pub_semver:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pub_semver
|
||||||
|
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.4"
|
||||||
|
pubspec_parse:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pubspec_parse
|
||||||
|
sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.3"
|
||||||
|
rust_core:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: rust_core
|
||||||
|
sha256: "3b61f6e32dc8af47dc8fa27b662c5ace9db713fd4dd5e9fd77400e6577d51fb8"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.5.3"
|
||||||
|
shelf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf
|
||||||
|
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.1"
|
||||||
|
shelf_web_socket:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_web_socket
|
||||||
|
sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -317,6 +605,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.0"
|
||||||
|
source_gen:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_gen
|
||||||
|
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.5.0"
|
||||||
|
source_helper:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_helper
|
||||||
|
sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.4"
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -349,6 +653,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.2"
|
||||||
|
stream_transform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stream_transform
|
||||||
|
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -381,6 +693,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.1"
|
version: "0.6.1"
|
||||||
|
timing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: timing
|
||||||
|
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
tuple:
|
tuple:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -493,6 +813,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "13.0.0"
|
version: "13.0.0"
|
||||||
|
watcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: watcher
|
||||||
|
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
web:
|
web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
15
pubspec.yaml
15
pubspec.yaml
@ -39,10 +39,14 @@ dependencies:
|
|||||||
yaml: ^3.1.2
|
yaml: ^3.1.2
|
||||||
surrealdb: ^0.8.0
|
surrealdb: ^0.8.0
|
||||||
geojson: ^1.0.0
|
geojson: ^1.0.0
|
||||||
flutter_map: ^4.0.0
|
flutter_map: 7.0.0-dev.1
|
||||||
latlong2: ^0.8.2
|
# latlong2: ^0.9.0
|
||||||
url_launcher: ^6.2.6
|
url_launcher: ^6.2.6
|
||||||
anim_search_bar: ^2.0.3
|
anim_search_bar: ^2.0.3
|
||||||
|
freezed_annotation: ^2.4.1
|
||||||
|
json_annotation: ^4.8.1
|
||||||
|
rust_core: ^0.5.3
|
||||||
|
anyhow: ^1.3.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@ -54,6 +58,9 @@ dev_dependencies:
|
|||||||
# package. See that file for information about deactivating specific lint
|
# package. See that file for information about deactivating specific lint
|
||||||
# rules and activating additional ones.
|
# rules and activating additional ones.
|
||||||
flutter_lints: ^3.0.0
|
flutter_lints: ^3.0.0
|
||||||
|
build_runner: ^2.4.9
|
||||||
|
freezed: ^2.5.2
|
||||||
|
json_serializable: ^6.7.1
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
@ -67,7 +74,9 @@ flutter:
|
|||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|
||||||
# To add assets to your application, add an assets section, like this:
|
# To add assets to your application, add an assets section, like this:
|
||||||
# assets:
|
assets:
|
||||||
|
# - assets/geo/
|
||||||
|
- assets/geo/uulm_beta.geojson
|
||||||
# - images/a_dot_burr.jpeg
|
# - images/a_dot_burr.jpeg
|
||||||
# - images/a_dot_ham.jpeg
|
# - images/a_dot_ham.jpeg
|
||||||
|
|
||||||
|
1
test/geojson_tests.dart
Normal file
1
test/geojson_tests.dart
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
Loading…
Reference in New Issue
Block a user