diff --git a/.gitignore b/.gitignore
index 1336b68..1a9b0d4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,4 +44,8 @@ app.*.map.json
/android/app/release
key.properties
-/key
\ No newline at end of file
+/key
+
+later.*
+
+to_remember.txt
\ No newline at end of file
diff --git a/assets/compass.svg b/assets/compass.svg
new file mode 100644
index 0000000..918efdd
--- /dev/null
+++ b/assets/compass.svg
@@ -0,0 +1,962 @@
+
+
+
+
diff --git a/assets/needle.svg b/assets/needle.svg
new file mode 100644
index 0000000..254f57a
--- /dev/null
+++ b/assets/needle.svg
@@ -0,0 +1,71 @@
+
+
+
+
\ No newline at end of file
diff --git a/lib/boxes/compass.dart b/lib/boxes/compass.dart
new file mode 100644
index 0000000..2189363
--- /dev/null
+++ b/lib/boxes/compass.dart
@@ -0,0 +1,133 @@
+import 'dart:async';
+import 'dart:ffi';
+import 'dart:math';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:ju_rc_app/lib/boxes.dart';
+import 'package:ju_rc_app/lib/sensors.dart';
+import 'package:ju_rc_app/lib/serial.dart';
+
+// c-structs
+base class GnssLocData extends Struct {
+ @Uint8()
+ external int type;
+ @Uint8()
+ external int command;
+
+ @Int32()
+ external int X;
+ @Int32()
+ external int Y;
+ @Int32()
+ external int Z;
+ @Int32()
+ external int angle;
+}
+// end c-structs
+
+class Compass extends JuBox {
+ const Compass({super.key});
+
+ @override
+ State createState() => _CompassState();
+}
+
+class _CompassState extends State {
+ USerial serial = getSerial();
+ late Timer timer;
+
+ int _magX = 0, _magY = 0, _magZ = 0, _magAngle = 0;
+
+ @override
+ void initState() {
+ super.initState();
+ SensorReader.listen(serialListen);
+ timer = Timer.periodic(const Duration(milliseconds: 500), (_) async {
+ serial.sprintln("2200", system: true);
+ });
+ }
+
+ @override
+ void dispose() {
+ SensorReader.removeListen(serialListen);
+ timer.cancel();
+ super.dispose();
+ }
+
+ void serialListen(int type, int command, Pointer ptr) {
+ if (type != 0x22 || command != 0x00) return;
+ var loc = ptr as Pointer;
+ setState(() {
+ _magX = loc.ref.X;
+ _magY = loc.ref.Y;
+ _magZ = loc.ref.Z;
+ int newAngle = loc.ref.angle;
+ if (newAngle - _magAngle > 200) newAngle -= 360;
+ if (newAngle - _magAngle < -200) newAngle += 360;
+ _magAngle = newAngle;
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) => Stack(
+ children: [
+ SvgPicture.asset('assets/compass.svg'),
+ AnimatedRotation(
+ turns: _magAngle / 360.0,
+ duration: const Duration(milliseconds: 500),
+ alignment: Alignment.center, // Rotate around the center
+ child: SvgPicture.asset('assets/needle.svg')),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ "x: ${(_magX * 8.0 / 32768.0 * 100.0).toStringAsFixed(2)}µT"),
+ Text(
+ "y: ${(_magY * 8.0 / 32768.0 * 100.0).toStringAsFixed(2)}µT"),
+ Text(
+ "z: ${(_magZ * 8.0 / 32768.0 * 100.0).toStringAsFixed(2)}µT"),
+ Expanded(
+ child: Align(
+ alignment: Alignment.bottomLeft,
+ child: FilledButton(
+ child: const Icon(Icons.calculate),
+ onPressed: () {
+ showDialog(
+ context: context,
+ builder: (BuildContext context) => AlertDialog(
+ title: const Text('Callibrate Compass'),
+ content: const Text(
+ 'When clicking okay the compass will be calibrated, \ncompletely blocking all radio communication for 10 sec. \nWhile calibrating rotate the sensor in ever direction.'),
+ actions: [
+ TextButton(
+ onPressed: () => Navigator.pop(context, 'Cancel'),
+ child: const Text('Cancel'),
+ ),
+ TextButton(
+ onPressed: () {
+ serial.sprintln("2201",
+ system: true);
+ Navigator.pop(context, 'OK');
+ },
+ child: const Text('OK'),
+ ),
+ ],
+ ),
+ );
+ //
+ },
+ ),
+ ),
+ ),
+ ],
+ ),
+ Expanded(
+ child: Align(
+ alignment: Alignment.topRight,
+ child: Text(
+ "t: ${(sqrt(_magX * _magX + _magY * _magY + _magZ * _magZ) * 8.0 / 32768.0 * 100.0).toStringAsFixed(2)}µT"),
+ ))
+ ],
+ );
+}
diff --git a/lib/boxes/maps.dart b/lib/boxes/maps.dart
new file mode 100644
index 0000000..217e323
--- /dev/null
+++ b/lib/boxes/maps.dart
@@ -0,0 +1,475 @@
+import 'dart:async';
+import 'dart:io';
+import 'package:flutter/material.dart';
+
+import 'dart:ffi';
+import 'package:flutter_map/flutter_map.dart';
+import 'package:latlong2/latlong.dart';
+
+import 'package:ju_rc_app/lib/boxes.dart';
+import 'package:ju_rc_app/lib/sensors.dart';
+import 'package:ju_rc_app/lib/serial.dart';
+
+// c-structs
+base class GnssLocData extends Struct {
+ @Uint8()
+ external int type;
+ @Uint8()
+ external int command;
+
+ @Uint8()
+ external int isValid;
+
+ @Double()
+ external double lat;
+ @Double()
+ external double lng;
+}
+
+base class SpeedLocData extends Struct {
+ @Uint8()
+ external int type;
+ @Uint8()
+ external int command;
+
+ @Uint8()
+ external int isValid;
+
+ @Double()
+ external double speed;
+}
+
+base class CourseLocData extends Struct {
+ @Uint8()
+ external int type;
+ @Uint8()
+ external int command;
+
+ @Uint8()
+ external int isValid;
+
+ @Double()
+ external double course;
+}
+
+base class AltLocData extends Struct {
+ @Uint8()
+ external int type;
+ @Uint8()
+ external int command;
+
+ @Uint8()
+ external int isValid;
+
+ @Double()
+ external double alt;
+}
+
+base class SatLocData extends Struct {
+ @Uint8()
+ external int type;
+ @Uint8()
+ external int command;
+
+ @Uint8()
+ external int isValid;
+
+ @Uint32()
+ external int n;
+}
+
+base class HdopLocData extends Struct {
+ @Uint8()
+ external int type;
+ @Uint8()
+ external int command;
+
+ @Uint8()
+ external int isValid;
+
+ @Double()
+ external double hdop;
+}
+
+// c-structs end
+
+class Maps extends JuBox {
+ const Maps({super.key});
+
+ @override
+ State createState() => _MapsState();
+}
+
+class _MapsState extends State with TickerProviderStateMixin {
+ USerial serial = getSerial();
+ late Timer timer;
+
+ double _lat = 51.1667, _long = 10.4500;
+ int _state = 0;
+ bool _wasVaild = false;
+ final _mapController = MapController();
+
+ @override
+ void initState() {
+ super.initState();
+ SensorReader.listen(serialListen);
+ timer = Timer.periodic(const Duration(seconds: 1), (_) async {
+ serial.sprintln("2300", system: true);
+ });
+ }
+
+ @override
+ void dispose() {
+ SensorReader.removeListen(serialListen);
+ timer.cancel();
+ super.dispose();
+ }
+
+ void serialListen(int type, int command, Pointer ptr) {
+ if (type != 0x23 || command != 0x00) return;
+ var loc = ptr as Pointer;
+ setState(() {
+ _lat = loc.ref.lat;
+ _long = loc.ref.lng;
+ _state = loc.ref.isValid;
+ //_mapController.move(LatLng(_lat, _long), _wasVaild ? 17 : 6);
+ _animatedMapMove(
+ _mapController, this, LatLng(_lat, _long), _wasVaild ? 17 : 6);
+ if (_state & 1 > 0) _wasVaild = true;
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) => FlutterMap(
+ options: MapOptions(
+ center: LatLng(_lat, _long),
+ zoom: _wasVaild ? 17 : 6,
+ maxZoom: _wasVaild ? 17 : 6,
+ minZoom: _wasVaild ? 17 : 6,
+ interactiveFlags: InteractiveFlag.none,
+ onTap: (TapPosition pos, LatLng ll) {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => const SerialDetailPage()),
+ );
+ }),
+ mapController: _mapController,
+ children: [
+ TileLayer(
+ urlTemplate: 'https://tile.openstreetmap.de/{z}/{x}/{y}.png',
+ userAgentPackageName: 'de.jusax.ju_rc_app',
+ ),
+ MarkerLayer(
+ markers: [
+ Marker(
+ point: LatLng(_lat, _long),
+ width: 100,
+ height: 100,
+ builder: (context) => Icon(
+ switch (_state) {
+ 3 => Icons.location_on,
+ 2 => Icons.location_off,
+ 1 => Icons.location_on_outlined,
+ int() => Icons.location_off_outlined,
+ },
+ color: Theme.of(context).colorScheme.primary,
+ ),
+ ),
+ ],
+ ),
+ ],
+ );
+}
+
+class SerialDetailPage extends StatefulWidget {
+ const SerialDetailPage({super.key});
+
+ @override
+ State createState() => _SerialDetailPageState();
+}
+
+class _SerialDetailPageState extends State
+ with TickerProviderStateMixin {
+ USerial serial = getSerial();
+ late Timer timer;
+ final _mapController = MapController();
+
+ double _lat = 51.1667, _long = 10.4500;
+ int _state = 0;
+
+ double _mps = -1, _course = -1, _alt = -1, _hdop = -1;
+ bool _mpsState = false,
+ _courseState = false,
+ _altState = false,
+ _satNState = false,
+ _hdopState = false;
+ int _satN = -1;
+ bool _follow = true;
+
+ @override
+ void initState() {
+ super.initState();
+ timer = Timer.periodic(const Duration(seconds: 2), (_) async {
+ serial.sprintln("2303", system: true);
+ sleep(const Duration(milliseconds: 200));
+ serial.sprintln("2304", system: true);
+ sleep(const Duration(milliseconds: 200));
+ serial.sprintln("2305", system: true);
+ sleep(const Duration(milliseconds: 200));
+ serial.sprintln("2306", system: true);
+ sleep(const Duration(milliseconds: 200));
+ serial.sprintln("2307", system: true);
+ });
+ SensorReader.listen(serialListen);
+ }
+
+ @override
+ void dispose() {
+ SensorReader.removeListen(serialListen);
+ timer.cancel();
+ super.dispose();
+ }
+
+ void serialListen(int type, int command, Pointer ptr) {
+ if (type != 0x23) return;
+ switch (command) {
+ case 0:
+ {
+ var loc = ptr as Pointer;
+ setState(() {
+ _lat = loc.ref.lat;
+ _long = loc.ref.lng;
+ _state = loc.ref.isValid;
+ if (_follow) {
+ _animatedMapMove(_mapController, this, LatLng(_lat, _long),
+ _mapController.zoom,
+ currentZoom: true);
+ }
+ });
+ }
+ break;
+ case 3:
+ {
+ var loc = ptr as Pointer;
+ setState(() {
+ _mps = loc.ref.speed;
+ _mpsState = loc.ref.isValid == 3;
+ });
+ }
+ break;
+ case 4:
+ {
+ var loc = ptr as Pointer;
+ setState(() {
+ _course = loc.ref.course;
+ _courseState = loc.ref.isValid == 3;
+ });
+ }
+ break;
+ case 5:
+ {
+ var loc = ptr as Pointer;
+ setState(() {
+ _alt = loc.ref.alt;
+ _altState = loc.ref.isValid == 3;
+ });
+ }
+ break;
+ case 6:
+ {
+ var loc = ptr as Pointer;
+ setState(() {
+ _satN = loc.ref.n;
+ _satNState = loc.ref.isValid == 3;
+ });
+ }
+ break;
+ case 7:
+ {
+ var loc = ptr as Pointer;
+ setState(() {
+ _hdop = loc.ref.hdop;
+ _hdopState = loc.ref.isValid == 3;
+ });
+ }
+ break;
+ case 0xff:
+ {}
+ break;
+ }
+ }
+
+ int shade() {
+ return MediaQuery.of(context).platformBrightness == Brightness.light
+ ? 100
+ : 800;
+ }
+
+ @override
+ Widget build(BuildContext context) => Scaffold(
+ appBar: AppBar(
+ backgroundColor: Theme.of(context).colorScheme.inversePrimary,
+ title: const Text(
+ "Maps",
+ style: TextStyle(
+ fontSize: 16,
+ ),
+ ),
+ toolbarHeight: 40,
+ ),
+ floatingActionButton: FloatingActionButton(
+ onPressed: () {
+ setState(() {
+ if (!_follow) _mapController.move(LatLng(_lat, _long), 17);
+ _follow = !_follow;
+ });
+ },
+ child: Icon(_follow ? Icons.near_me : Icons.near_me_outlined),
+ ),
+ body: Column(children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Text(
+ "Speed: ${_mps.toStringAsPrecision(3)}m/s",
+ style: TextStyle(
+ backgroundColor:
+ _mpsState ? Colors.green[shade()] : Colors.red[shade()]),
+ ),
+ const VerticalDivider(width: 5),
+ Text("Course: ${_course.toStringAsFixed(0)}°",
+ style: TextStyle(
+ backgroundColor: _courseState
+ ? Colors.green[shade()]
+ : Colors.red[shade()])),
+ const VerticalDivider(width: 5),
+ Text("Alt: ${_alt.toStringAsPrecision(4)}m",
+ style: TextStyle(
+ backgroundColor: _altState
+ ? Colors.green[shade()]
+ : Colors.red[shade()])),
+ const VerticalDivider(width: 5),
+ Text("Sats: $_satN",
+ style: TextStyle(
+ backgroundColor: _satNState
+ ? Colors.green[shade()]
+ : Colors.red[shade()])),
+ const VerticalDivider(width: 5),
+ Text("Hdop: ${_hdop.toStringAsPrecision(2)}",
+ style: TextStyle(
+ backgroundColor: _hdopState
+ ? Colors.green[shade()]
+ : Colors.red[shade()])),
+ ],
+ ),
+ Expanded(
+ child: FlutterMap(
+ mapController: _mapController,
+ options: MapOptions(
+ center: const LatLng(51.1667, 10.4500),
+ zoom: 6,
+ maxZoom: 18,
+ interactiveFlags: InteractiveFlag.drag |
+ InteractiveFlag.flingAnimation |
+ InteractiveFlag.pinchMove |
+ InteractiveFlag.pinchZoom |
+ InteractiveFlag.doubleTapZoom,
+ onPositionChanged: (MapPosition pos, bool user) {
+ if (user) {
+ setState(() {
+ _follow = false;
+ });
+ }
+ }),
+ children: [
+ TileLayer(
+ urlTemplate: 'https://tile.openstreetmap.de/{z}/{x}/{y}.png',
+ //urlTemplate: 'https://sgx.geodatenzentrum.de/wmts_basemapde/tile/1.0.0/de_basemapde_web_raster_farbe/default/GLOBAL_WEBMERCATOR/{z}/{y}/{x}.png',
+ userAgentPackageName: 'de.jusax.ju_rc_app',
+ ),
+ MarkerLayer(
+ markers: [
+ Marker(
+ point: LatLng(_lat, _long),
+ width: 100,
+ height: 100,
+ builder: (context) => Transform.rotate(
+ angle: _course *
+ (pi / 180), // Convert degrees to radians
+ child: Icon(
+ switch (_state) {
+ 3 => Icons.navigation,
+ 2 => Icons.location_off,
+ 1 => Icons.navigation_outlined,
+ int() => Icons.location_off_outlined,
+ },
+ color: Theme.of(context).colorScheme.primary,
+ ),
+ )),
+ ],
+ ),
+ ],
+ ))
+ ]));
+}
+
+// animated Map from Map lib provider
+
+void _animatedMapMove(MapController mapController, TickerProvider ticker,
+ LatLng destLocation, double destZoom,
+ {bool currentZoom = false}) {
+ const startedId = 'AnimatedMapController#MoveStarted';
+ const inProgressId = 'AnimatedMapController#MoveInProgress';
+ const finishedId = 'AnimatedMapController#MoveFinished';
+ // Create some tweens. These serve to split up the transition from one location to another.
+ // In our case, we want to split the transition be our current map center and the destination.
+ final camera = mapController;
+ final latTween =
+ Tween(begin: camera.center.latitude, end: destLocation.latitude);
+ final lngTween = Tween(
+ begin: camera.center.longitude, end: destLocation.longitude);
+ final zoomTween = Tween(begin: camera.zoom, end: destZoom);
+
+ // Create a animation controller that has a duration and a TickerProvider.
+ final controller = AnimationController(
+ duration: const Duration(milliseconds: 500), vsync: ticker);
+ // The animation determines what path the animation will take. You can try different Curves values, although I found
+ // fastOutSlowIn to be my favorite.
+ final Animation animation =
+ CurvedAnimation(parent: controller, curve: Curves.fastOutSlowIn);
+
+ // Note this method of encoding the target destination is a workaround.
+ // When proper animated movement is supported (see #1263) we should be able
+ // to detect an appropriate animated movement event which contains the
+ // target zoom/center.
+ final startIdWithTarget =
+ '$startedId#${destLocation.latitude},${destLocation.longitude},$destZoom';
+ bool hasTriggeredMove = false;
+
+ controller.addListener(() {
+ final String id;
+ if (animation.value == 1.0) {
+ id = finishedId;
+ } else if (!hasTriggeredMove) {
+ id = startIdWithTarget;
+ } else {
+ id = inProgressId;
+ }
+ hasTriggeredMove |= mapController.move(
+ LatLng(latTween.evaluate(animation), lngTween.evaluate(animation)),
+ currentZoom ? mapController.zoom : zoomTween.evaluate(animation),
+ id: id,
+ );
+ });
+
+ animation.addStatusListener((status) {
+ if (status == AnimationStatus.completed) {
+ controller.dispose();
+ } else if (status == AnimationStatus.dismissed) {
+ controller.dispose();
+ }
+ });
+
+ controller.forward();
+}
diff --git a/lib/lib/sensors.dart b/lib/lib/sensors.dart
new file mode 100644
index 0000000..fe3ea6a
--- /dev/null
+++ b/lib/lib/sensors.dart
@@ -0,0 +1,51 @@
+import 'package:ju_rc_app/lib/boxes.dart';
+import 'package:ju_rc_app/lib/serial.dart';
+import 'package:convert/convert.dart';
+import 'dart:ffi';
+import 'package:ffi/ffi.dart';
+
+base class ArrayCStruct extends Struct {
+ @Array(32)
+ external Array buffer;
+}
+
+class SensorReader {
+ static USerial serial = getSerial();
+
+ static final List)> _callback = [];
+
+ static void _serialListen(String line, SerialCommand? cmdo) {
+ if (cmdo == null) return;
+ var cmd = cmdo;
+ if (cmd.command != "rfSystemSensor") return;
+ if (cmd.arg == "lost") print("lost");
+ if (["noconn", "lost", "send"].contains(cmd.arg)) return;
+ final bytes = hex.decode(cmd.arg);
+ final Pointer buffer = calloc();
+ for (int i = 0; i < bytes.length && i < 32; i++) {
+ buffer.ref.buffer[i] = bytes[i];
+ }
+ for (var fnk in _callback) {
+ fnk(buffer.ref.buffer[0], buffer.ref.buffer[1], buffer);
+ }
+ calloc.free(buffer);
+ }
+
+ static bool _active = false;
+
+ static void listen(Function(int, int, Pointer) callback) {
+ _callback.add(callback);
+ if (!_active) {
+ _active = true;
+ serial.listen(_serialListen);
+ }
+ }
+
+ static void removeListen(Function(int, int, Pointer) callback) {
+ _callback.remove(callback);
+ if (_callback.isEmpty) {
+ _active = false;
+ serial.removeListen(_serialListen);
+ }
+ }
+}
diff --git a/lib/lib/serial.dart b/lib/lib/serial.dart
index 63a1570..461cc44 100644
--- a/lib/lib/serial.dart
+++ b/lib/lib/serial.dart
@@ -50,7 +50,7 @@ abstract class USerial {
}
LimitedList<(SerialMessageType, DateTime, String)> lines =
- LimitedList(524288);
+ LimitedList(1024);
final List _callback = [];
void _receive(String line) {
lines.add((SerialMessageType.received, DateTime.now(), line));
diff --git a/lib/main.dart b/lib/main.dart
index 5964297..270dcde 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,7 +1,9 @@
import 'dart:io';
import 'package:flutter/material.dart';
+import 'package:ju_rc_app/boxes/compass.dart';
import 'package:ju_rc_app/boxes/console.dart';
+import 'package:ju_rc_app/boxes/maps.dart';
import 'package:ju_rc_app/boxes/state.dart';
import 'package:ju_rc_app/connector.dart';
import 'package:ju_rc_app/lib/boxes.dart';
@@ -45,7 +47,12 @@ class MyHomePage extends StatefulWidget {
class _MyHomePageState extends State {
ConnectionBar conBar = ConnectionBar();
- static List boxes = [const SerialBox(), const ControllerState()];
+ static List boxes = [
+ const ControllerState(),
+ const Maps(),
+ const Compass(),
+ const SerialBox(),
+ ];
@override
void initState() {
diff --git a/pubspec.lock b/pubspec.lock
index 58eff46..d77a540 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -74,7 +74,7 @@ packages:
source: hosted
version: "1.18.0"
convert:
- dependency: transitive
+ dependency: "direct main"
description:
name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
@@ -114,7 +114,7 @@ packages:
source: hosted
version: "1.3.1"
ffi:
- dependency: transitive
+ dependency: "direct main"
description:
name: ffi
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
@@ -150,6 +150,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.3"
+ flutter_map:
+ dependency: "direct main"
+ description:
+ name: flutter_map
+ sha256: "5286f72f87deb132daa1489442d6cc46e986fc105cb727d9ae1b602b35b1d1f3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.0.0"
+ flutter_svg:
+ dependency: "direct main"
+ description:
+ name: flutter_svg
+ sha256: "8c5d68a82add3ca76d792f058b186a0599414f279f00ece4830b9b231b570338"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.7"
flutter_test:
dependency: "direct dev"
description: flutter
@@ -216,6 +232,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.8.1"
+ latlong2:
+ dependency: "direct main"
+ description:
+ name: latlong2
+ sha256: "18712164760cee655bc790122b0fd8f3d5b3c36da2cb7bf94b68a197fbb0811b"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.9.0"
libserialport:
dependency: transitive
description:
@@ -232,6 +256,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.1"
+ lists:
+ dependency: transitive
+ description:
+ name: lists
+ sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.1"
matcher:
dependency: transitive
description:
@@ -256,6 +288,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.1"
+ mgrs_dart:
+ dependency: transitive
+ description:
+ name: mgrs_dart
+ sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.0"
path:
dependency: transitive
description:
@@ -264,6 +304,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.8.3"
+ path_parsing:
+ dependency: transitive
+ description:
+ name: path_parsing
+ sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.1"
petitparser:
dependency: transitive
description:
@@ -296,14 +344,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.7.3"
+ polylabel:
+ dependency: transitive
+ description:
+ name: polylabel
+ sha256: "41b9099afb2aa6c1730bdd8a0fab1400d287694ec7615dd8516935fa3144214b"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.1"
+ proj4dart:
+ dependency: transitive
+ description:
+ name: proj4dart
+ sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.0"
rive:
dependency: "direct main"
description:
name: rive
- sha256: "5fbb92f9f880cddbb9181342dc24099eee323ca43339e2c8e1ae6fad85df915e"
+ sha256: f2117a96a189758bc79bf7933865625c7a44a420ae537d2a8f6c492900136a71
url: "https://pub.dev"
source: hosted
- version: "0.11.16"
+ version: "0.11.17"
rive_common:
dependency: transitive
description:
@@ -373,6 +437,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.2"
+ unicode:
+ dependency: transitive
+ description:
+ name: unicode
+ sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.3.1"
usb_serial:
dependency: "direct main"
description:
@@ -381,6 +453,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.5.1"
+ vector_graphics:
+ dependency: transitive
+ description:
+ name: vector_graphics
+ sha256: "670f6e07aca990b4a2bcdc08a784193c4ccdd1932620244c3a86bb72a0eac67f"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.7"
+ vector_graphics_codec:
+ dependency: transitive
+ description:
+ name: vector_graphics_codec
+ sha256: "7451721781d967db9933b63f5733b1c4533022c0ba373a01bdd79d1a5457f69f"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.7"
+ vector_graphics_compiler:
+ dependency: transitive
+ description:
+ name: vector_graphics_compiler
+ sha256: "80a13c613c8bde758b1464a1755a7b3a8f2b6cec61fbf0f5a53c94c30f03ba2e"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.7"
vector_math:
dependency: transitive
description:
@@ -397,6 +493,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.1.4-beta"
+ wkt_parser:
+ dependency: transitive
+ description:
+ name: wkt_parser
+ sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.0"
xml:
dependency: transitive
description:
@@ -415,4 +519,4 @@ packages:
version: "3.1.2"
sdks:
dart: ">=3.1.0-185.0.dev <4.0.0"
- flutter: ">=3.0.0"
+ flutter: ">=3.10.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index 7a3ccb6..b2dafdb 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -39,6 +39,11 @@ dependencies:
usb_serial: ^0.5.1
rive: ^0.11.16
intl: ^0.18.1
+ ffi: ^2.1.0
+ convert: ^3.1.1
+ flutter_map: ^5.0.0
+ latlong2: ^0.9.0
+ flutter_svg: ^2.0.7
dev_dependencies:
flutter_test:
@@ -74,6 +79,9 @@ flutter_launcher_icons:
# The following section is specific to Flutter packages.
flutter:
+ assets:
+ - assets/compass.svg
+ - assets/needle.svg
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in