Copy old project - initial state
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'eov.dart';
|
||||
|
||||
class ConvertCoordinate {
|
||||
static double _dms2Rad(double d) {
|
||||
double d2 = 648000 / pi;
|
||||
double d3 = d * 10000;
|
||||
var d4 = (d3 / 10000).floor();
|
||||
double d5 = d3 - d4 * 10000;
|
||||
var d6 = (d5 / 100).floor();
|
||||
double d7 = d5 - d6 * 100;
|
||||
d5 = (d4 * 3600 + d6 * 60 + d7) / d2;
|
||||
|
||||
return d5;
|
||||
}
|
||||
|
||||
static List<double> _ellXyz(
|
||||
double fiRad, double laRad, double ad1, double ad2, double d, double d1) {
|
||||
double d2 = (d * d - d1 * d1) / (d * d);
|
||||
double d3 = d / sqrt(1.0 - d2 * sin(fiRad) * sin(fiRad));
|
||||
double d4 = ad1 + ad2;
|
||||
List<double> result = List.filled(3, 0);
|
||||
|
||||
result[0] = (d3 + d4) * cos(fiRad) * cos(laRad);
|
||||
result[1] = (d3 + d4) * cos(fiRad) * sin(laRad);
|
||||
result[2] = (d3 * (1.0 - d2) + d4) * sin(fiRad);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static List<double> _eurefHd72(List<double> ad) {
|
||||
double d = 1.000000000005822;
|
||||
double d1 = 1.0000010190999999;
|
||||
double ad3_0 = ad[0] - 52.683999999999997;
|
||||
double ad3_1 = ad[1] - -71.194000000000003;
|
||||
double ad3_2 = ad[2] - -13.975;
|
||||
double ad2_0 = (1.0000000000022879 * ad3_0 +
|
||||
-1.8078694373184586E-006 * ad3_1 +
|
||||
5.1535967763767014E-007 * ad3_2) /
|
||||
d;
|
||||
double ad2_1 = (1.0000000000002656 * ad3_1 +
|
||||
1.8078709963955414E-006 * ad3_0 +
|
||||
-1.5126177533635316E-006 * ad3_2) /
|
||||
d;
|
||||
double ad2_2 = (1.0000000000032685 * ad3_2 +
|
||||
-5.153542084011298E-007 * ad3_0 +
|
||||
1.5126196167604682E-006 * ad3_1) /
|
||||
d;
|
||||
List<double> ad1 = List.filled(3, 0);
|
||||
ad1[0] = ad2_0 / d1;
|
||||
ad1[1] = ad2_1 / d1;
|
||||
ad1[2] = ad2_2 / d1;
|
||||
|
||||
return ad1;
|
||||
}
|
||||
|
||||
static List<double> _xyzEll(List<double> ad, double d, double d1) {
|
||||
double d6;
|
||||
List<double> ad1 = List.filled(2, 0);
|
||||
List<double> ad2 = List.filled(2, 0);
|
||||
|
||||
double d2 = (d * d - d1 * d1) / (d * d);
|
||||
double d3 = sqrt(ad[0] * ad[0] + ad[1] * ad[1]);
|
||||
double d4 = d;
|
||||
double d5 = 9.9999999999999995E-007;
|
||||
ad2[0] = 0.0;
|
||||
ad1[1] = atan2(ad[1], ad[0]);
|
||||
do {
|
||||
double d7 = ad[2] / d3;
|
||||
double d8 = 1.0 - (d2 * d4) / (d4 + ad2[0]);
|
||||
ad1[0] = atan2(d7, d8);
|
||||
d4 = d / sqrt(1.0 - d2 * sin(ad1[0]) * sin(ad1[0]));
|
||||
ad2[0] = d3 / cos(ad1[0]) - d4;
|
||||
d6 = (d4 * (1.0 - d2) + ad2[0]) * sin(ad1[0]) - ad[2];
|
||||
ad2[0] = ad2[0] - d6;
|
||||
} while (d6.abs() > d5);
|
||||
|
||||
return [...ad1, ...ad2];
|
||||
}
|
||||
|
||||
static List<double> _iuggFilaFila1(List<double> ad1) {
|
||||
List<double> ad = List.filled(2, 0);
|
||||
double d = pi;
|
||||
d = d / 4;
|
||||
double d1 = sqrt(0.0066946053569177958);
|
||||
double d2 = sin(0.82321363052399998) / sin(0.82243820885649999);
|
||||
double d3 = _iuggK();
|
||||
double d4 = ad1[0] / 2 + d;
|
||||
double d5 = tan(d4);
|
||||
double d6 = pow(d5, d2).toDouble();
|
||||
d4 = (1.0 - d1 * sin(ad1[0])) / (1.0 + d1 * sin(ad1[0]));
|
||||
d5 = (d2 * d1) / 2;
|
||||
double d7 = pow(d4, d5).toDouble();
|
||||
d4 = d3 * d6 * d7;
|
||||
d5 = atan(d4);
|
||||
d4 = d5 - d;
|
||||
ad[0] = 2 * d4;
|
||||
ad[1] = d2 * (ad1[1] - 0.33246029532470001);
|
||||
|
||||
return ad;
|
||||
}
|
||||
|
||||
static double _iuggK() {
|
||||
double d = pi;
|
||||
double d2 = sqrt(0.0066946053569177958);
|
||||
double d1 = sin(0.82321363052399998) / sin(0.82243820885649999);
|
||||
d = d / 4;
|
||||
double d3 = tan(0.41121910442824999 + d);
|
||||
double d4 = tan(0.41160681526199999 + d);
|
||||
double d5 = pow(d4, d1).toDouble();
|
||||
d4 = d5;
|
||||
d5 = (1.0 - d2 * sin(0.82321363052399998)) /
|
||||
(1.0 + d2 * sin(0.82321363052399998));
|
||||
double d6 = (d1 * d2) / 2;
|
||||
double d7 = pow(d5, d6).toDouble();
|
||||
d5 = d7 * d4;
|
||||
return d3 / d5;
|
||||
}
|
||||
|
||||
static Eov _iuggFilaXy(List<double> ad1) {
|
||||
double d = pi;
|
||||
double d1 = 0.99992999999999999;
|
||||
d = d / 4;
|
||||
double d2 = _iuggR();
|
||||
List<double> ad2 = List.filled(2, 0);
|
||||
ad2 = _gaussSgomb(ad1);
|
||||
double d3 = d + ad2[0] / 2;
|
||||
double eovx =
|
||||
d1 * d2 * (log(tan(d3)) / log(2.7182818284590452354)) + 200000;
|
||||
double eovy = d1 * d2 * ad2[1] + 650000;
|
||||
|
||||
return Eov(eovx, eovy);
|
||||
}
|
||||
|
||||
static double _iuggR() {
|
||||
double d = sqrt(0.0066946053569177958);
|
||||
double d1 =
|
||||
sqrt(1.0 - d * d * sin(0.82321363052399998) * sin(0.82321363052399998));
|
||||
double d2 = 6378160 / d1;
|
||||
d1 = 40680924985600 * cos(0.82321363052399998) * cos(0.82321363052399998) +
|
||||
40408582247267.031 *
|
||||
sin(0.82321363052399998) *
|
||||
sin(0.82321363052399998);
|
||||
double d3 = pow(d1, 1.5).toDouble();
|
||||
double d4 = 1.6438585031755181E+027 / d3;
|
||||
return sqrt(d4 * d2);
|
||||
}
|
||||
|
||||
static List<double> _gaussSgomb(List<double> ad1) {
|
||||
List<double> ad = List.filled(2, 0);
|
||||
|
||||
ad[0] = asin(sin(ad1[0]) * cos(0.82205007768930005) -
|
||||
cos(ad1[0]) * cos(ad1[1]) * sin(0.82205007768930005));
|
||||
ad[1] = asin((cos(ad1[0]) * sin(ad1[1])) / cos(ad[0]));
|
||||
|
||||
return ad;
|
||||
}
|
||||
|
||||
static int toDegree(double a) {
|
||||
return a.toInt();
|
||||
}
|
||||
|
||||
static int toMinute(double a) {
|
||||
return ((a - toDegree(a)) * 60.0).toInt();
|
||||
}
|
||||
|
||||
static double toSecond(double a) {
|
||||
return ((a - toDegree(a)) * 60.0 - toMinute(a)) * 60.0;
|
||||
}
|
||||
|
||||
static Eov ConvertWgsToEov(double fi, double la) {
|
||||
List<double> wgs84 = List.filled(4, 0);
|
||||
List<double> xyz = List.filled(3, 0);
|
||||
List<double> fila = List.filled(2, 0);
|
||||
List<double> fila1 = List.filled(2, 0);
|
||||
|
||||
double fi11 = toDegree(fi).toDouble();
|
||||
double fip11 = toMinute(fi).toDouble();
|
||||
double fimp11 = toSecond(fi);
|
||||
|
||||
double la11 = toDegree(la).toDouble();
|
||||
double lap11 = toMinute(la).toDouble();
|
||||
double lamp11 = toSecond(la);
|
||||
|
||||
double fi1 = fi11 + (fip11 / 100) + (fimp11 / 10000);
|
||||
double la1 = la11 + (lap11 / 100) + (lamp11 / 10000);
|
||||
|
||||
double fiRad = _dms2Rad(fi1);
|
||||
double laRad = _dms2Rad(la1);
|
||||
wgs84 = _ellXyz(fiRad, laRad, 0, 0, 6378137.0, 6356752.3141400004);
|
||||
xyz = _eurefHd72(wgs84);
|
||||
fila = _xyzEll(xyz, 6378160, 6356774.5159999998);
|
||||
fila1 = _iuggFilaFila1(fila);
|
||||
|
||||
return _iuggFilaXy(fila1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class Eov {
|
||||
double X = 0;
|
||||
double Y = 0;
|
||||
|
||||
Eov(this.X, this.Y);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import 'package:nmea/nmea.dart';
|
||||
|
||||
class Gngga extends TalkerSentence {
|
||||
static const String id = "GNGGA";
|
||||
Gngga({required super.raw});
|
||||
|
||||
@override
|
||||
bool get valid => super.valid && fields.length == 15;
|
||||
|
||||
String get utcOfPositionFix => fields[1];
|
||||
int get gpsQualityIndicator => int.parse(fields[6]);
|
||||
double get latitude => _getCoordinateFromGpsLatitude(fields[2]);
|
||||
String get latitudeDirection => fields[3];
|
||||
double get longitude => _getCoordinateFromGpsLongitude(fields[4]);
|
||||
String get longitudeDirection => fields[5];
|
||||
int get numberOfSvsInUse => int.parse(fields[7]);
|
||||
double get hdop => double.parse(fields[8]);
|
||||
double get altitudeAboveMeanSeaLevel => double.parse(fields[9]);
|
||||
double get geoidSeparation => double.parse(fields[11]);
|
||||
|
||||
double _getCoordinateFromGpsLongitude(String coordinate) {
|
||||
double result =
|
||||
double.parse("${coordinate[0]}${coordinate[1]}${coordinate[2]}") +
|
||||
double.parse(coordinate.substring(3)) / 60;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
double _getCoordinateFromGpsLatitude(String coordinate) {
|
||||
double result = double.parse("${coordinate[0]}${coordinate[1]}") +
|
||||
double.parse(coordinate.substring(2)) / 60;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import 'package:nmea/nmea.dart';
|
||||
|
||||
class Gngst extends TalkerSentence {
|
||||
static const String id = "GNGST";
|
||||
Gngst({required super.raw});
|
||||
|
||||
@override
|
||||
bool get valid => super.valid && fields.length == 9;
|
||||
|
||||
String get utcOfPositionFix => fields[1];
|
||||
double get rms => double.parse(fields[2]);
|
||||
double get errorEllipseSemiMajorAxis => double.parse(fields[3]);
|
||||
double get errorEllipseSemiMinorAxis => double.parse(fields[4]);
|
||||
double get errorEllipseOrientation => double.parse(fields[5]);
|
||||
double get longitudeError => double.parse(fields[6]);
|
||||
double get latitudeError => double.parse(fields[7]);
|
||||
double get heightError => double.parse(fields[8]);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import 'package:nmea/nmea.dart';
|
||||
|
||||
class Gnrmc extends TalkerSentence {
|
||||
static const String id = "GNRMC";
|
||||
Gnrmc({required super.raw});
|
||||
|
||||
@override
|
||||
bool get valid => super.valid && fields.length == 14;
|
||||
|
||||
String get messageId => fields[0];
|
||||
String get utcOfPositionFix => fields[1];
|
||||
String get Status => fields[2];
|
||||
double get latitude => _getCoordinateFromGpsLatitude(fields[3]);
|
||||
String get latitudeDirection => fields[4];
|
||||
double get longitude => _getCoordinateFromGpsLongitude(fields[5]);
|
||||
String get longitudeDirection => fields[6];
|
||||
double get speedOverGroundKnots => double.parse(fields[7]);
|
||||
double get courseOverGround => double.parse(fields[8]);
|
||||
String get date => fields[9];
|
||||
double get magneticVariation => double.parse(fields[10]);
|
||||
String get magneticVariationDirection => fields[11];
|
||||
String get positioningSystemModeIndicator => fields[12];
|
||||
|
||||
double _getCoordinateFromGpsLongitude(String coordinate) {
|
||||
double result =
|
||||
double.parse("${coordinate[0]}${coordinate[1]}${coordinate[2]}") +
|
||||
double.parse(coordinate.substring(3)) / 60;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
double _getCoordinateFromGpsLatitude(String coordinate) {
|
||||
double result = double.parse("${coordinate[0]}${coordinate[1]}") +
|
||||
double.parse(coordinate.substring(2)) / 60;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'package:terepi_seged/routes/app_pages.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await Firebase.initializeApp();
|
||||
|
||||
await Supabase.initialize(
|
||||
url: 'https://supa.app-dev.hu',
|
||||
anonKey:
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ewogICJyb2xlIjogImFub24iLAogICJpc3MiOiAic3VwYWJhc2UiLAogICJpYXQiOiAxNzExMDYyMDAwLAogICJleHAiOiAxODY4ODI4NDAwCn0.XWtP3eEysZDxXjaHHUZyyhw0n4YZo_xWUMWS5ajBcbI');
|
||||
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetMaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.blue[600]),
|
||||
enableLog: true,
|
||||
initialRoute: AppPages.INITIAL,
|
||||
getPages: AppPages.routes,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
|
||||
|
||||
class BluetoothDeviceListEntry extends ListTile {
|
||||
BluetoothDeviceListEntry({super.key,
|
||||
required BluetoothDevice device,
|
||||
int? rssi,
|
||||
GestureTapCallback? onTap,
|
||||
GestureLongPressCallback? onLongPress,
|
||||
bool enabled = true,
|
||||
}) : super(
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
enabled: enabled,
|
||||
leading:
|
||||
const Icon(Icons.devices), // @TODO . !BluetoothClass! class aware icon
|
||||
title: Text(device.name ?? "Unknown device"),
|
||||
subtitle: Text(device.address.toString()),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
rssi != null
|
||||
? Container(
|
||||
margin: const EdgeInsets.all(8.0),
|
||||
child: DefaultTextStyle(
|
||||
style: _computeTextStyle(rssi),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Text(rssi.toString()),
|
||||
const Text('dBm'),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: const SizedBox(width: 0, height: 0),
|
||||
device.isConnected
|
||||
? const Icon(Icons.import_export)
|
||||
: const SizedBox(width: 0, height: 0),
|
||||
device.isBonded
|
||||
? const Icon(Icons.link)
|
||||
: const SizedBox(width: 0, height: 0),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
static TextStyle _computeTextStyle(int rssi) {
|
||||
/**/ if (rssi >= -35) {
|
||||
return TextStyle(color: Colors.greenAccent[700]);
|
||||
} else if (rssi >= -45) {
|
||||
return TextStyle(
|
||||
color: Color.lerp(
|
||||
Colors.greenAccent[700], Colors.lightGreen, -(rssi + 35) / 10));
|
||||
} else if (rssi >= -55) {
|
||||
return TextStyle(
|
||||
color: Color.lerp(
|
||||
Colors.lightGreen, Colors.lime[600], -(rssi + 45) / 10));
|
||||
} else if (rssi >= -65) {
|
||||
return TextStyle(
|
||||
color: Color.lerp(Colors.lime[600], Colors.amber, -(rssi + 55) / 10));
|
||||
} else if (rssi >= -75) {
|
||||
return TextStyle(
|
||||
color: Color.lerp(
|
||||
Colors.amber, Colors.deepOrangeAccent, -(rssi + 65) / 10));
|
||||
} else if (rssi >= -85) {
|
||||
return TextStyle(
|
||||
color: Color.lerp(
|
||||
Colors.deepOrangeAccent, Colors.redAccent, -(rssi + 75) / 10));
|
||||
} else {
|
||||
/*code symetry*/
|
||||
return const TextStyle(color: Colors.redAccent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||
import 'dart:convert';
|
||||
|
||||
class PointToMeasure {
|
||||
int id;
|
||||
double coordX;
|
||||
double coordY;
|
||||
PointToMeasure({
|
||||
required this.id,
|
||||
required this.coordX,
|
||||
required this.coordY,
|
||||
});
|
||||
|
||||
PointToMeasure copyWith({
|
||||
int? id,
|
||||
double? coordX,
|
||||
double? coordY,
|
||||
}) {
|
||||
return PointToMeasure(
|
||||
id: id ?? this.id,
|
||||
coordX: coordX ?? this.coordX,
|
||||
coordY: coordY ?? this.coordY,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return <String, dynamic>{
|
||||
'id': id,
|
||||
'coordX': coordX,
|
||||
'coordY': coordY,
|
||||
};
|
||||
}
|
||||
|
||||
factory PointToMeasure.fromMap(Map<String, dynamic> map) {
|
||||
return PointToMeasure(
|
||||
id: map['id'] as int,
|
||||
coordX: map['coordX'] as double,
|
||||
coordY: map['coordY'] as double,
|
||||
);
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory PointToMeasure.fromJson(String source) =>
|
||||
PointToMeasure.fromMap(json.decode(source) as Map<String, dynamic>);
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'PointToMeasure(id: $id, coordX: $coordX, coordY: $coordY)';
|
||||
|
||||
@override
|
||||
bool operator ==(covariant PointToMeasure other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other.id == id && other.coordX == coordX && other.coordY == coordY;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => id.hashCode ^ coordX.hashCode ^ coordY.hashCode;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
class PointWithDescription {
|
||||
final int Id;
|
||||
final DateTime dateTime;
|
||||
final String description;
|
||||
final double eovX;
|
||||
final double eovY;
|
||||
final double latitude;
|
||||
final double longitude;
|
||||
final double horizontalError;
|
||||
final double verticalError;
|
||||
|
||||
PointWithDescription(
|
||||
this.Id,
|
||||
this.dateTime,
|
||||
this.description,
|
||||
this.eovX,
|
||||
this.eovY,
|
||||
this.latitude,
|
||||
this.longitude,
|
||||
this.horizontalError,
|
||||
this.verticalError);
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
||||
import 'dart:convert';
|
||||
import 'dart:ffi';
|
||||
|
||||
class SeismicRecord {
|
||||
const SeismicRecord({
|
||||
required this.ffid,
|
||||
required this.gpsDateTime,
|
||||
required this.gpsTimeInMicroseconds,
|
||||
required this.imageUrl,
|
||||
required this.maxReceiverPointFduNumber,
|
||||
required this.minReceiverPointFduNumber,
|
||||
required this.minReceiverPointNumber,
|
||||
required this.maxReceiverPointNumber,
|
||||
required this.sourceLine,
|
||||
required this.sourcePoint,
|
||||
});
|
||||
|
||||
final int ffid;
|
||||
final DateTime gpsDateTime;
|
||||
final int gpsTimeInMicroseconds;
|
||||
final String imageUrl;
|
||||
final int maxReceiverPointFduNumber;
|
||||
final int minReceiverPointFduNumber;
|
||||
final int minReceiverPointNumber;
|
||||
final int maxReceiverPointNumber;
|
||||
final double sourceLine;
|
||||
final double sourcePoint;
|
||||
|
||||
SeismicRecord copyWith({
|
||||
int? ffid,
|
||||
DateTime? gpsDateTime,
|
||||
int? gpsTimeInMicroseconds,
|
||||
String? imageUrl,
|
||||
int? maxReceiverPointFduNumber,
|
||||
int? minReceiverPointFduNumber,
|
||||
int? minReceiverPointNumber,
|
||||
int? maxReceiverPointNumber,
|
||||
double? sourceLine,
|
||||
double? sourcePoint,
|
||||
}) {
|
||||
return SeismicRecord(
|
||||
ffid: ffid ?? this.ffid,
|
||||
gpsDateTime: gpsDateTime ?? this.gpsDateTime,
|
||||
gpsTimeInMicroseconds:
|
||||
gpsTimeInMicroseconds ?? this.gpsTimeInMicroseconds,
|
||||
imageUrl: imageUrl ?? this.imageUrl,
|
||||
maxReceiverPointFduNumber:
|
||||
maxReceiverPointFduNumber ?? this.maxReceiverPointFduNumber,
|
||||
minReceiverPointFduNumber:
|
||||
minReceiverPointFduNumber ?? this.minReceiverPointFduNumber,
|
||||
minReceiverPointNumber:
|
||||
minReceiverPointNumber ?? this.minReceiverPointNumber,
|
||||
maxReceiverPointNumber:
|
||||
maxReceiverPointNumber ?? this.maxReceiverPointNumber,
|
||||
sourceLine: sourceLine ?? this.sourceLine,
|
||||
sourcePoint: sourcePoint ?? this.sourcePoint,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return <String, dynamic>{
|
||||
'ffid': ffid,
|
||||
'gpsDateTime': gpsDateTime.millisecondsSinceEpoch,
|
||||
'gpsTimeInMicroseconds': gpsTimeInMicroseconds,
|
||||
'imageUrl': imageUrl,
|
||||
'maxReceiverPointFduNumber': maxReceiverPointFduNumber,
|
||||
'minReceiverPointFduNumber': minReceiverPointFduNumber,
|
||||
'minReceiverPointNumber': minReceiverPointNumber,
|
||||
'maxReceiverPointNumber': maxReceiverPointNumber,
|
||||
'sourceLine': sourceLine,
|
||||
'sourcePoint': sourcePoint,
|
||||
};
|
||||
}
|
||||
|
||||
factory SeismicRecord.fromMap(Map<String, dynamic> map) {
|
||||
return SeismicRecord(
|
||||
ffid: map['ffid'] as int,
|
||||
gpsDateTime:
|
||||
DateTime.fromMillisecondsSinceEpoch(map['gpsDateTime'] as int),
|
||||
gpsTimeInMicroseconds: map['gpsTimeInMicroseconds'] as int,
|
||||
imageUrl: map['imageUrl'] as String,
|
||||
maxReceiverPointFduNumber: map['maxReceiverPointFduNumber'] as int,
|
||||
minReceiverPointFduNumber: map['minReceiverPointFduNumber'] as int,
|
||||
minReceiverPointNumber: map['minReceiverPointNumber'] as int,
|
||||
maxReceiverPointNumber: map['maxReceiverPointNumber'] as int,
|
||||
sourceLine: map['sourceLine'] as double,
|
||||
sourcePoint: map['sourcePoint'] as double,
|
||||
);
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory SeismicRecord.fromJson(String source) =>
|
||||
SeismicRecord.fromMap(json.decode(source) as Map<String, dynamic>);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SeismicRecord(ffid: $ffid, gpsDateTime: $gpsDateTime, gpsTimeInMicroseconds: $gpsTimeInMicroseconds, imageUrl: $imageUrl, maxReceiverPointFduNumber: $maxReceiverPointFduNumber, minReceiverPointFduNumber: $minReceiverPointFduNumber, minReceiverPointNumber: $minReceiverPointNumber, maxReceiverPointNumber: $maxReceiverPointNumber, sourceLine: $sourceLine, sourcePoint: $sourcePoint)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(covariant SeismicRecord other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other.ffid == ffid &&
|
||||
other.gpsDateTime == gpsDateTime &&
|
||||
other.gpsTimeInMicroseconds == gpsTimeInMicroseconds &&
|
||||
other.imageUrl == imageUrl &&
|
||||
other.maxReceiverPointFduNumber == maxReceiverPointFduNumber &&
|
||||
other.minReceiverPointFduNumber == minReceiverPointFduNumber &&
|
||||
other.minReceiverPointNumber == minReceiverPointNumber &&
|
||||
other.maxReceiverPointNumber == maxReceiverPointNumber &&
|
||||
other.sourceLine == sourceLine &&
|
||||
other.sourcePoint == sourcePoint;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return ffid.hashCode ^
|
||||
gpsDateTime.hashCode ^
|
||||
gpsTimeInMicroseconds.hashCode ^
|
||||
imageUrl.hashCode ^
|
||||
maxReceiverPointFduNumber.hashCode ^
|
||||
minReceiverPointFduNumber.hashCode ^
|
||||
minReceiverPointNumber.hashCode ^
|
||||
maxReceiverPointNumber.hashCode ^
|
||||
sourceLine.hashCode ^
|
||||
sourcePoint.hashCode;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/bleutooth/presentation/controllers/bluetooth_controller.dart';
|
||||
|
||||
class BluetoothTestBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => BluetoothTestViewController());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:nmea/nmea.dart';
|
||||
import 'package:terepi_seged/gnss_sentences/gngga.dart';
|
||||
|
||||
class BluetoothTestViewController extends GetxController {
|
||||
Rx<BluetoothState> bluetoothState = BluetoothState.UNKNOWN.obs;
|
||||
RxList<BluetoothDevice> devices = RxList<BluetoothDevice>([]);
|
||||
Rx<BluetoothDevice>? selectedDevice;
|
||||
final NmeaDecoder nmeaDecoder = NmeaDecoder();
|
||||
|
||||
BluetoothConnection? connection;
|
||||
StreamSubscription<BluetoothDiscoveryResult>? _bluetoothDiscoveryStream;
|
||||
RxList<BluetoothDiscoveryResult> bluetoothDiscoveryResults =
|
||||
RxList<BluetoothDiscoveryResult>.empty(growable: true);
|
||||
|
||||
// bool get isConnected => connection != null && connection!.isConnected;
|
||||
bool isConnected = false;
|
||||
int count = 0;
|
||||
String _messageBuffer = '';
|
||||
bool hasGpsData = false;
|
||||
DateTime lastGpsRefreshTime = DateTime.now();
|
||||
RxString utcOfPositionFix = "".obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
|
||||
print("Call BluetoothTestController.OnInit");
|
||||
|
||||
FlutterBluetoothSerial.instance.state.then((state) {
|
||||
bluetoothState.value = state;
|
||||
if (bluetoothState.value.isEnabled) {
|
||||
//_listBoundedDevices();
|
||||
_startDiscovery();
|
||||
}
|
||||
});
|
||||
nmeaDecoder.registerTalkerSentence("GGA", (line) => Gngga(raw: line));
|
||||
|
||||
//Loading, Success, Error handle with 1 line of code
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
super.onClose();
|
||||
FlutterBluetoothSerial.instance.setPairingRequestHandler(null);
|
||||
if (isConnected) {
|
||||
connection?.close();
|
||||
// connection = null;
|
||||
print("BluetoothTestController dispose ....");
|
||||
}
|
||||
}
|
||||
|
||||
_listBoundedDevices() {
|
||||
FlutterBluetoothSerial.instance
|
||||
.getBondedDevices()
|
||||
.then((List<BluetoothDevice> boundedDevices) {
|
||||
devices.value = boundedDevices;
|
||||
devices.refresh();
|
||||
});
|
||||
}
|
||||
|
||||
void setSelectedDevice(BluetoothDevice device) {
|
||||
selectedDevice = Rx<BluetoothDevice>(device);
|
||||
|
||||
if (!isConnected) {
|
||||
BluetoothConnection.toAddress(selectedDevice?.value.address)
|
||||
.then((value) {
|
||||
connection = value;
|
||||
isConnected = true;
|
||||
print("Bleutooth device connected .... ${connection!.isConnected}");
|
||||
|
||||
connection!.input!.listen(_onDataReceived);
|
||||
});
|
||||
|
||||
// connection!.input!.listen((data) {
|
||||
// print("Data -> $data");
|
||||
// });
|
||||
}
|
||||
}
|
||||
|
||||
void _startDiscovery() {
|
||||
_bluetoothDiscoveryStream =
|
||||
FlutterBluetoothSerial.instance.startDiscovery().listen((event) {
|
||||
final existingIndex = bluetoothDiscoveryResults.indexWhere(
|
||||
(element) => element.device.address == event.device.address);
|
||||
if (existingIndex > 0) {
|
||||
bluetoothDiscoveryResults[existingIndex] = event;
|
||||
update();
|
||||
} else {
|
||||
bluetoothDiscoveryResults.add(event);
|
||||
update();
|
||||
}
|
||||
});
|
||||
|
||||
_bluetoothDiscoveryStream!.onDone(() {});
|
||||
}
|
||||
|
||||
void _onDataReceived(Uint8List data) {
|
||||
// Allocate buffer for parsed data
|
||||
int backspacesCounter = 0;
|
||||
String sentence = '';
|
||||
|
||||
// print("Data: $data");
|
||||
|
||||
for (var byte in data) {
|
||||
if (byte == 8 || byte == 127) {
|
||||
backspacesCounter++;
|
||||
}
|
||||
}
|
||||
Uint8List buffer = Uint8List(data.length - backspacesCounter);
|
||||
int bufferIndex = buffer.length;
|
||||
|
||||
// Apply backspace control character
|
||||
backspacesCounter = 0;
|
||||
for (int i = data.length - 1; i >= 0; i--) {
|
||||
if (data[i] == 8 || data[i] == 127) {
|
||||
backspacesCounter++;
|
||||
} else {
|
||||
if (backspacesCounter > 0) {
|
||||
backspacesCounter--;
|
||||
} else {
|
||||
buffer[--bufferIndex] = data[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create message if there is new line character
|
||||
String dataString = String.fromCharCodes(buffer);
|
||||
int index = buffer.indexOf(13);
|
||||
if (~index != 0) {
|
||||
sentence = backspacesCounter > 0
|
||||
? _messageBuffer.substring(
|
||||
0, _messageBuffer.length - backspacesCounter)
|
||||
: _messageBuffer + dataString.substring(0, index);
|
||||
_messageBuffer = dataString.substring(index);
|
||||
} else {
|
||||
_messageBuffer = (backspacesCounter > 0
|
||||
? _messageBuffer.substring(
|
||||
0, _messageBuffer.length - backspacesCounter)
|
||||
: _messageBuffer + dataString);
|
||||
}
|
||||
|
||||
count++;
|
||||
// print("Message ($count): $sentence");
|
||||
_processGnssMessage(sentence);
|
||||
}
|
||||
|
||||
void _processGnssMessage(String message) {
|
||||
LineSplitter lineSplitter = const LineSplitter();
|
||||
List<String> lines = lineSplitter.convert(message);
|
||||
|
||||
if (lines.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String line in lines) {
|
||||
if (line.trim().isEmpty) {
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("\$GNGGA")) {
|
||||
final sentence = nmeaDecoder.decode(line);
|
||||
if (sentence!.valid && sentence is Gngga) {
|
||||
hasGpsData = sentence.gpsQualityIndicator > 0;
|
||||
if (hasGpsData) {
|
||||
if (DateTime.now().difference(lastGpsRefreshTime).inSeconds >= 4) {
|
||||
lastGpsRefreshTime = DateTime.now();
|
||||
utcOfPositionFix.value = sentence.utcOfPositionFix;
|
||||
}
|
||||
print("Last update: $utcOfPositionFix");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/models/bluetooth_device_list_entry.dart';
|
||||
import 'package:terepi_seged/pages/bleutooth/presentation/controllers/bluetooth_controller.dart';
|
||||
|
||||
class BluetoothTestView extends GetView<BluetoothTestViewController> {
|
||||
const BluetoothTestView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: Scaffold(
|
||||
extendBody: true,
|
||||
backgroundColor: Colors.black.withOpacity(0.05),
|
||||
appBar: AppBar(
|
||||
elevation: 0.0,
|
||||
title: const Text('BluetoothTest'),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back_ios),
|
||||
color: Colors.white,
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
),
|
||||
),
|
||||
body: Column(children: [
|
||||
const Center(
|
||||
child: Text("BluetoothTestView"),
|
||||
),
|
||||
ListTile(
|
||||
title: const Text(
|
||||
'Bluetooth status',
|
||||
),
|
||||
subtitle: Obx(() => Text("${controller.bluetoothState}")),
|
||||
trailing: ElevatedButton(
|
||||
child: const Text('Settings'),
|
||||
onPressed: () {
|
||||
FlutterBluetoothSerial.instance.openSettings();
|
||||
},
|
||||
),
|
||||
),
|
||||
Obx(() => Text(
|
||||
"${controller.bluetoothState}",
|
||||
style: TextStyle(
|
||||
color: controller.bluetoothState.value.isEnabled
|
||||
? Colors.green
|
||||
: Colors.red),
|
||||
)),
|
||||
Obx(() => Text("Last update: ${controller.utcOfPositionFix}",
|
||||
style: const TextStyle(
|
||||
color: Colors.blue, fontWeight: FontWeight.bold))),
|
||||
Expanded(
|
||||
child: Obx(
|
||||
() => ListView(
|
||||
children: controller.bluetoothDiscoveryResults
|
||||
.map((device) => BluetoothDeviceListEntry(
|
||||
device: device.device,
|
||||
enabled: true,
|
||||
onTap: () {
|
||||
print("Device: ${device.device.address}");
|
||||
controller.setSelectedDevice(device.device);
|
||||
},
|
||||
))
|
||||
.toList()),
|
||||
))
|
||||
])));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../presentation/controllers/home_controller.dart';
|
||||
|
||||
class HomeBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => HomeViewController());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
class HomeViewController extends GetxController {
|
||||
Rx<PackageInfo> packageInfo = PackageInfo(
|
||||
appName: 'Unknown',
|
||||
packageName: 'Unknown',
|
||||
version: 'Unknown',
|
||||
buildNumber: 'Unknown',
|
||||
buildSignature: 'Unknown',
|
||||
installerStore: 'Unknown',
|
||||
).obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
_initPackageInfo();
|
||||
super.onInit();
|
||||
//Loading, Success, Error handle with 1 line of code
|
||||
}
|
||||
|
||||
Future<void> _initPackageInfo() async {
|
||||
final info = await PackageInfo.fromPlatform();
|
||||
packageInfo.value = info;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/home/presentation/controllers/home_controller.dart';
|
||||
import 'package:terepi_seged/pages/home/presentation/widgets/big_button_widget.dart';
|
||||
|
||||
class HomeView extends GetView<HomeViewController> {
|
||||
const HomeView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: Scaffold(
|
||||
extendBody: true,
|
||||
backgroundColor: Colors.black.withOpacity(0.05),
|
||||
appBar: AppBar(
|
||||
elevation: 0.0,
|
||||
title: const Text('Kezdőlap'),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back_ios),
|
||||
color: Colors.white,
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
),
|
||||
),
|
||||
body: Column(children: [
|
||||
Column(
|
||||
children: const [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10.0),
|
||||
child: Center(
|
||||
child: Text("Kezdőlap"),
|
||||
),
|
||||
),
|
||||
// TextButton(
|
||||
// onPressed: () async {
|
||||
// Get.toNamed('/map');
|
||||
// },
|
||||
// child: const Text('Map')),
|
||||
// TextButton(
|
||||
// onPressed: () async {
|
||||
// Get.toNamed('/bluetooth_test');
|
||||
// },
|
||||
// child: const Text('Bluetooth test')),
|
||||
// TextButton(
|
||||
// onPressed: () async {
|
||||
// Get.toNamed('/socket_test');
|
||||
// },
|
||||
// child: const Text('Socket teszt')),
|
||||
// TextButton(
|
||||
// onPressed: () async {
|
||||
// Get.toNamed('/rtcm_test');
|
||||
// },
|
||||
// child: const Text('RTCM teszt'))
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
BigButtonWidget(
|
||||
iconData: Icons.flag,
|
||||
label: "Kitűzés",
|
||||
onPressed: () async {
|
||||
Get.toNamed('/map');
|
||||
},
|
||||
),
|
||||
BigButtonWidget(
|
||||
iconData: Icons.monitor_heart,
|
||||
label: "Mérés",
|
||||
onPressed: () async {
|
||||
Get.toNamed("/measured_data");
|
||||
// ScaffoldMessenger.of(context)
|
||||
// .showSnackBar(const SnackBar(
|
||||
// content: Text(
|
||||
// "Fejlesztlés alatt",
|
||||
// style: TextStyle(fontWeight: FontWeight.bold),
|
||||
// ),
|
||||
// backgroundColor: Colors.black54,
|
||||
// ));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
BigButtonWidget(
|
||||
iconData: Icons.navigation,
|
||||
label: "Navigáció",
|
||||
onPressed: () async {
|
||||
Get.toNamed('/navigation');
|
||||
// ScaffoldMessenger.of(context)
|
||||
// .showSnackBar(const SnackBar(
|
||||
// content: Text(
|
||||
// "Fejlesztlés alatt",
|
||||
// style: TextStyle(fontWeight: FontWeight.bold),
|
||||
// ),
|
||||
// backgroundColor: Colors.black54,
|
||||
// ));
|
||||
},
|
||||
),
|
||||
BigButtonWidget(
|
||||
iconData: Icons.message,
|
||||
label: "Üzenetek",
|
||||
onPressed: () async {
|
||||
// Get.toNamed("/navigation");
|
||||
ScaffoldMessenger.of(context)
|
||||
.showSnackBar(const SnackBar(
|
||||
content: Text(
|
||||
"Fejlesztlés alatt",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
backgroundColor: Colors.black54,
|
||||
));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
BigButtonWidget(
|
||||
iconData: Icons.house,
|
||||
label: "Ingatlanok",
|
||||
onPressed: () async {
|
||||
// Get.toNamed('/map_test');
|
||||
ScaffoldMessenger.of(context)
|
||||
.showSnackBar(const SnackBar(
|
||||
content: Text(
|
||||
"Fejlesztlés alatt",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
backgroundColor: Colors.black54,
|
||||
));
|
||||
},
|
||||
),
|
||||
BigButtonWidget(
|
||||
iconData: Icons.edit_road,
|
||||
label: "Track",
|
||||
onPressed: () async {
|
||||
// Get.toNamed("/navigation");
|
||||
ScaffoldMessenger.of(context)
|
||||
.showSnackBar(const SnackBar(
|
||||
content: Text(
|
||||
"Fejlesztlés alatt",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
backgroundColor: Colors.black54,
|
||||
));
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Obx(
|
||||
() => Text(
|
||||
"Verzió: ${controller.packageInfo.value.version}+${controller.packageInfo.value.buildNumber}",
|
||||
style: const TextStyle(fontSize: 12)),
|
||||
)
|
||||
],
|
||||
)
|
||||
])));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class BigButtonWidget extends StatelessWidget {
|
||||
const BigButtonWidget(
|
||||
{Key? key, required this.iconData, required this.label, this.onPressed})
|
||||
: super(key: key);
|
||||
|
||||
final IconData iconData;
|
||||
final String label;
|
||||
final Function()? onPressed;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return OutlinedButton(
|
||||
onPressed: onPressed,
|
||||
style: ButtonStyle(
|
||||
minimumSize: MaterialStateProperty.all(const Size(130, 140)),
|
||||
maximumSize: MaterialStateProperty.all(const Size(130, 140)),
|
||||
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
|
||||
const RoundedRectangleBorder(borderRadius: BorderRadius.zero))),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(8.0, 10.0, 8.0, 4.0),
|
||||
child: Icon(
|
||||
iconData,
|
||||
color: Colors.blueGrey,
|
||||
size: 64,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
label,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: Colors.blueGrey, fontWeight: FontWeight.bold),
|
||||
))
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/map/presentation/controllers/map_controller.dart';
|
||||
|
||||
class MapBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => MapViewController());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,890 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:flutter_map_geojson/flutter_map_geojson.dart';
|
||||
import 'package:flutter_map_polywidget/flutter_map_polywidget.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:location/location.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:nmea/nmea.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:permission_handler/permission_handler.dart'
|
||||
as permission_handler;
|
||||
import 'package:terepi_seged/eov/convert_coordinate.dart';
|
||||
import 'package:terepi_seged/eov/eov.dart';
|
||||
import 'package:terepi_seged/gnss_sentences/gngga.dart';
|
||||
import 'package:terepi_seged/gnss_sentences/gngst.dart';
|
||||
import 'package:terepi_seged/gnss_sentences/gnrmc.dart';
|
||||
import 'package:terepi_seged/models/point_to_measure.dart';
|
||||
import 'package:terepi_seged/models/point_with_description_model.dart';
|
||||
import 'package:proj4dart/proj4dart.dart' as proj4;
|
||||
|
||||
class MapViewController extends GetxController {
|
||||
// String gpsAddress = "E8:31:CD:14:8B:B2";
|
||||
// String gpsAddress = "98:CD:AC:62:FF:4E";
|
||||
RxString gpsAddress = "98:CD:AC:62:FF:36".obs;
|
||||
String gpsName = "TiGNSS Rover-FF4E";
|
||||
// String gpsName = "TiGNSS Rover-8BB2";
|
||||
static const double maxZoomValue = 25.0;
|
||||
Rx<bool> gpsIsConnected = false.obs;
|
||||
RxBool ntripIsConnected = false.obs;
|
||||
RxInt ntripDataPacketNumbers = 0.obs;
|
||||
RxInt ggaSenDataPacketNumber = 0.obs;
|
||||
RxString ggaSendLastTimeStr = "".obs;
|
||||
String _messageBuffer = "";
|
||||
late BluetoothConnection connection;
|
||||
late Socket socket;
|
||||
late StreamSubscription socketStreamSubscription;
|
||||
RxInt gpsReceivedData = 0.obs;
|
||||
RxBool hasGpsValidData = false.obs;
|
||||
RxBool isMapMoveToCenter = true.obs;
|
||||
DateTime lastGpsRefreshTime = DateTime.now();
|
||||
String utcOfPositionFix = "";
|
||||
String utcDateOfPositionFix = "";
|
||||
RxInt ntripReceivedData = 0.obs;
|
||||
final NmeaDecoder nmeaDecoder = NmeaDecoder();
|
||||
String lastGgaMessage = '';
|
||||
DateTime lastSendTimeGgaMessage =
|
||||
DateTime.now().add(const Duration(seconds: -30));
|
||||
|
||||
NumberFormat formatEov = NumberFormat("##0,000.0", "hu-HU");
|
||||
NumberFormat formatEovForFile = NumberFormat("#####0.0", "hu-HU");
|
||||
NumberFormat formatWgs84Sec = NumberFormat('00.000', 'hu-HU');
|
||||
|
||||
RxDouble gpsLatitude = 0.0.obs;
|
||||
RxString gpsLatitudeDirection = "".obs;
|
||||
RxDouble gpsLongitude = 0.0.obs;
|
||||
RxString gpsLongitudeDirection = "".obs;
|
||||
RxDouble gpsAltitude = 0.0.obs;
|
||||
RxInt gpsQuality = 0.obs;
|
||||
RxDouble gpsLatitudeError = 0.0.obs;
|
||||
RxDouble gpsLongitudeError = 0.0.obs;
|
||||
RxDouble gpsAltitudeError = 0.0.obs;
|
||||
Rx<DateTime> gpsDateTime = DateTime(2000).obs;
|
||||
Rx<Eov> eov = Eov(0, 0).obs;
|
||||
RxInt latDegree = 0.obs;
|
||||
RxInt latMin = 0.obs;
|
||||
RxDouble latSec = 0.0.obs;
|
||||
RxInt longDegree = 0.obs;
|
||||
RxInt longMin = 0.obs;
|
||||
RxDouble longSec = 0.0.obs;
|
||||
|
||||
RxDouble currentLongitude = 0.0.obs;
|
||||
RxDouble currentLatitude = 0.0.obs;
|
||||
RxDouble currentZoom = 12.0.obs;
|
||||
late final MapController mapController;
|
||||
final currentLocationMarker = <Marker>[];
|
||||
final pointNotesMarker = <Marker>[];
|
||||
|
||||
List<PointToMeasure> pointsToMeasure = <PointToMeasure>[];
|
||||
final pointsToMeasureMarker = <Marker>[];
|
||||
final pointsToMeasureLabel = <PolyWidget>[];
|
||||
final pointsToMeasureDropDownMenuItem = <DropdownMenuItem<int>>[];
|
||||
RxInt pointsToMeasureSelectedValue = (-1).obs;
|
||||
RxDouble distance = 0.0.obs;
|
||||
|
||||
TextEditingController pointIdController = TextEditingController();
|
||||
TextEditingController pointDescriptionController = TextEditingController();
|
||||
TextEditingController gpsHeightController = TextEditingController();
|
||||
TextEditingController pointPrefixController = TextEditingController();
|
||||
TextEditingController pointPostfixController = TextEditingController();
|
||||
TextEditingController ntripUsernameController = TextEditingController();
|
||||
TextEditingController ntripPasswordController = TextEditingController();
|
||||
|
||||
int pointId = 1;
|
||||
String pointIdPrefix = "";
|
||||
String pointIdPostfix = "";
|
||||
String ntripUserName = "";
|
||||
String ntripPassword = "";
|
||||
|
||||
Rx<bool> pointMeasuringDirectionForward = true.obs;
|
||||
|
||||
List<PointWithDescription> pointWithDescriptionList = [];
|
||||
late Directory? directory;
|
||||
late File dataFile;
|
||||
|
||||
late proj4.Projection eovProj, wgsProj;
|
||||
RxBool mapIsInitialized = false.obs;
|
||||
|
||||
GeoJsonParser parser = GeoJsonParser(defaultMarkerColor: Colors.yellow);
|
||||
|
||||
final CollectionReference _measuredPoints =
|
||||
FirebaseFirestore.instance.collection('measuredPoints');
|
||||
|
||||
// late SMIBool gpsTrigger;
|
||||
// late StateMachineController riveGpsIconController;
|
||||
|
||||
@override
|
||||
void onInit() async {
|
||||
super.onInit();
|
||||
final bytes = (await rootBundle.load('assets/Grids/etrs2eov_notowgs.gsb'))
|
||||
.buffer
|
||||
.asUint8List();
|
||||
proj4.Projection.nadgrid('Etrs2Eov', bytes);
|
||||
// var def =
|
||||
// '+proj=somerc +lat_0=47.14439372222222 +lon_0=19.04857177777778 +k_0=0.99993 +x_0=650000 +y_0=200000 +ellps=GRS67 +towgs84=52.17,-71.82,-14.9,0,0,0,0 +units=m +nadgrids=@ignorable,Etrs2Eov,null +no_defs';
|
||||
var def =
|
||||
'+proj=somerc +lat_0=47.14439372222222 +lon_0=19.04857177777778 +k_0=0.99993 +x_0=650000 +y_0=200000 +ellps=GRS67 +towgs84=52.17,-71.82,-14.9,0,0,0,0 +units=m +nadgrids=Etrs2Eov +no_defs';
|
||||
|
||||
// Named Projection signature, later find it from anywhere via Projection.get('EPSG:23700')
|
||||
eovProj = proj4.Projection.add('EPSG:23700', def);
|
||||
wgsProj = proj4.Projection.WGS84;
|
||||
//Loading, Success, Error handle with 1 line of code
|
||||
nmeaDecoder
|
||||
..registerTalkerSentence("GGA", (line) => Gngga(raw: line))
|
||||
..registerTalkerSentence("RMC", (line) => Gnrmc(raw: line))
|
||||
..registerTalkerSentence("GST", (line) => Gngst(raw: line));
|
||||
|
||||
mapController = MapController();
|
||||
|
||||
// riveGpsIconController = RiveUtils.getRiveController(Artboard(),
|
||||
// stateMachineName: "gps_Interactivity");
|
||||
// gpsTrigger = riveGpsIconController.findSMI("active");
|
||||
|
||||
mapIsInitialized.value = true;
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
super.onClose();
|
||||
FlutterBluetoothSerial.instance.setPairingRequestHandler(null);
|
||||
if (gpsIsConnected.value) {
|
||||
connection.close();
|
||||
// connection = null;
|
||||
print("BluetoothTestController dispose ....");
|
||||
}
|
||||
pointDescriptionController.dispose();
|
||||
pointIdController.dispose();
|
||||
gpsHeightController.dispose();
|
||||
pointPrefixController.dispose();
|
||||
pointPostfixController.dispose();
|
||||
ntripUsernameController.dispose();
|
||||
ntripPasswordController.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() async {
|
||||
super.onReady();
|
||||
|
||||
_getInitialLocation();
|
||||
|
||||
// String data = await rootBundle.loadString('assets/Files/transzekt.geojson');
|
||||
// parser.parseGeoJsonAsString(data);
|
||||
|
||||
if (await permission_handler.Permission.storage.isGranted) {
|
||||
print("Storage permission is ok ...");
|
||||
} else {
|
||||
var result = await permission_handler.Permission.storage.request();
|
||||
if (result == permission_handler.PermissionStatus.granted) {
|
||||
print("Storage permission request is ok ....");
|
||||
} else {
|
||||
print("No storage permission");
|
||||
}
|
||||
}
|
||||
if (await permission_handler.Permission.manageExternalStorage.isGranted) {
|
||||
print("External storage permission is ok ...");
|
||||
} else {
|
||||
var result =
|
||||
await permission_handler.Permission.manageExternalStorage.request();
|
||||
if (result == permission_handler.PermissionStatus.granted) {
|
||||
print("External storage permission request is ok ....");
|
||||
} else {
|
||||
print("No external storage permission");
|
||||
}
|
||||
}
|
||||
|
||||
directory = await getExternalStorageDirectory();
|
||||
print(directory!.path);
|
||||
// String newPath = '';
|
||||
// List<String> folders = directory!.path.split("/");
|
||||
// for (int i = 1; i < folders.length; i++) {
|
||||
// String folder = folders[i];
|
||||
// if (folder != "Android") {
|
||||
// newPath += "/" + folder;
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// newPath = newPath + "/TerepisSegedApp";
|
||||
// directory = Directory(newPath);
|
||||
if (!await directory!.exists()) {
|
||||
await directory!.create(recursive: true);
|
||||
}
|
||||
dataFile = File("${directory!.path}/data.txt");
|
||||
|
||||
if (await directory!.exists()) {
|
||||
if (!await dataFile.exists()) {
|
||||
dataFile.writeAsString(
|
||||
"Id;DateTime;Description;EovX;EovY;Latitude;Longitude;Altitude;Hor.Err;Vert.Err\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
gpsHeightController.text = '1.7';
|
||||
}
|
||||
|
||||
void _getInitialLocation() async {
|
||||
bool servicedEnabled;
|
||||
PermissionStatus permissionGranted;
|
||||
LocationData locationData;
|
||||
Location location = Location();
|
||||
|
||||
servicedEnabled = await location.serviceEnabled();
|
||||
if (!servicedEnabled) {
|
||||
servicedEnabled = await location.requestService();
|
||||
if (!servicedEnabled) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
permissionGranted = await location.hasPermission();
|
||||
if (permissionGranted == PermissionStatus.denied) {
|
||||
permissionGranted = await location.requestPermission();
|
||||
if (permissionGranted != PermissionStatus.granted) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
locationData = await location.getLocation();
|
||||
currentLatitude.value = locationData.latitude ?? 0.0;
|
||||
currentLongitude.value = locationData.longitude ?? 0.0;
|
||||
print("Current location initialized -> $currentLatitude $currentLongitude");
|
||||
mapController.move(LatLng(currentLatitude.value, currentLongitude.value),
|
||||
currentZoom.value);
|
||||
_updateCurrentLocationMarker();
|
||||
}
|
||||
|
||||
void connectToGps() {
|
||||
if (gpsIsConnected == false) {
|
||||
BluetoothConnection.toAddress(gpsAddress.value).then((value) {
|
||||
connection = value;
|
||||
gpsIsConnected.value = true;
|
||||
print("GPS is connected ...");
|
||||
|
||||
connection.input!.listen(_onDataReceived);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void disconnectFromGps() {
|
||||
if (gpsIsConnected.value) {
|
||||
connection.close();
|
||||
gpsIsConnected.value = false;
|
||||
print("GPS is disconnected ....");
|
||||
}
|
||||
if (ntripIsConnected.value) {
|
||||
disconnectFromNtripServer();
|
||||
}
|
||||
}
|
||||
|
||||
void connectToNtripServer() async {
|
||||
// socket = await Socket.connect(InternetAddress('3.23.52.207'), 2101,
|
||||
// timeout: const Duration(seconds: 5));
|
||||
socket = await Socket.connect(InternetAddress('84.206.45.44'), 2101,
|
||||
timeout: const Duration(seconds: 5));
|
||||
socket.asBroadcastStream;
|
||||
ntripIsConnected.value = true;
|
||||
|
||||
socket.encoding = ascii;
|
||||
print("Connected to ntrip server ....");
|
||||
|
||||
// String header = "GET /KOVARIK HTTP/1.1\r\n";
|
||||
String header = "GET /SGO_RTK3.2 HTTP/1.1\r\n";
|
||||
|
||||
header += "User-Agent: SharpGps iter.dk\r\n";
|
||||
header += "Accept: */*\r\nConnection: close\r\n";
|
||||
// header += "Authorization: Basic ${_toBase64("info@mail.app-dev.hu:")}\r\n";
|
||||
header += "Authorization: Basic ${_toBase64("elgi08:Laszl0stef1")}\r\n";
|
||||
// header += "Host:rtk2go.com:2101\r\n";
|
||||
header += "Host:gnssnet.hu:2101\r\n";
|
||||
header += "Ntrip-Vesrsion:Ntrip/2.0\r\n";
|
||||
header += "\r\n";
|
||||
|
||||
// listen for responses from the server
|
||||
socketStreamSubscription = socket.listen(
|
||||
// handle data from the server
|
||||
(Uint8List data) {
|
||||
// "ICY 200 OK" - first response
|
||||
final serverResponse = String.fromCharCodes(data);
|
||||
ntripReceivedData.value = data.length;
|
||||
ntripDataPacketNumbers.value++;
|
||||
if (gpsIsConnected.value) {
|
||||
if (data.length > 14) {
|
||||
connection.output.add(data);
|
||||
}
|
||||
}
|
||||
print('Server: $ntripReceivedData');
|
||||
},
|
||||
|
||||
// handle errors
|
||||
onError: (error) {
|
||||
print(error);
|
||||
socket.destroy();
|
||||
},
|
||||
|
||||
// handle server ending connection
|
||||
onDone: () async {
|
||||
print('Server left.');
|
||||
socketStreamSubscription.cancel();
|
||||
await socket.flush();
|
||||
ntripIsConnected.value = false;
|
||||
ntripReceivedData.value = 0;
|
||||
socket.destroy();
|
||||
},
|
||||
);
|
||||
|
||||
socket.add(_convertStringToUint8List(header));
|
||||
|
||||
// sendGgaMessage(lastGgaMessage);
|
||||
}
|
||||
|
||||
void disconnectFromNtripServer() async {
|
||||
socketStreamSubscription.cancel();
|
||||
await socket.flush();
|
||||
socket.close();
|
||||
socket.destroy();
|
||||
ntripReceivedData.value = 0;
|
||||
ntripIsConnected.value = false;
|
||||
print("Disconnect from ntrip server....");
|
||||
}
|
||||
|
||||
void _onDataReceived(Uint8List data) {
|
||||
String sentence = "";
|
||||
|
||||
print("Bluetooth received -> ${data.length} byte(s)");
|
||||
String dataString = String.fromCharCodes(data);
|
||||
int index = data.indexOf(13);
|
||||
|
||||
if (~index != 0) {
|
||||
sentence = _messageBuffer + dataString.substring(0, index);
|
||||
_messageBuffer = dataString.substring(index);
|
||||
} else {
|
||||
_messageBuffer = _messageBuffer + dataString;
|
||||
}
|
||||
|
||||
// print("Message ($count): $sentence");
|
||||
_processGnssMessage(sentence);
|
||||
}
|
||||
|
||||
String _toBase64(String str) {
|
||||
final bytes = ascii.encode(str);
|
||||
final base64Str = base64.encode(bytes);
|
||||
|
||||
return base64Str;
|
||||
}
|
||||
|
||||
Uint8List _convertStringToUint8List(String str) {
|
||||
final List<int> codeUnits = str.codeUnits;
|
||||
final Uint8List unit8List = Uint8List.fromList(codeUnits);
|
||||
return unit8List;
|
||||
}
|
||||
|
||||
void _processGnssMessage(String message) {
|
||||
LineSplitter lineSplitter = const LineSplitter();
|
||||
List<String> lines = lineSplitter.convert(message);
|
||||
|
||||
if (lines.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String line in lines) {
|
||||
if (line.trim().isEmpty) {
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("\$GNGGA")) {
|
||||
final sentence = nmeaDecoder.decode(line);
|
||||
if (sentence!.valid && sentence is Gngga) {
|
||||
hasGpsValidData.value = sentence.gpsQualityIndicator > 0;
|
||||
if (hasGpsValidData.value) {
|
||||
if (DateTime.now().difference(lastGpsRefreshTime).inSeconds >= 0) {
|
||||
lastGpsRefreshTime = DateTime.now();
|
||||
utcOfPositionFix = sentence.utcOfPositionFix;
|
||||
gpsLatitude.value = sentence.latitude;
|
||||
gpsLatitudeDirection.value = sentence.latitudeDirection;
|
||||
gpsLongitude.value = sentence.longitude;
|
||||
gpsLongitudeDirection.value = sentence.longitudeDirection;
|
||||
gpsAltitude.value = sentence.altitudeAboveMeanSeaLevel;
|
||||
gpsQuality.value = sentence.gpsQualityIndicator;
|
||||
eov.value = ConvertCoordinate.ConvertWgsToEov(
|
||||
gpsLatitude.value, gpsLongitude.value);
|
||||
|
||||
if (pointsToMeasureSelectedValue.value >= 0) {
|
||||
double coordX =
|
||||
pointsToMeasure[pointsToMeasureSelectedValue.value].coordX;
|
||||
double coordY =
|
||||
pointsToMeasure[pointsToMeasureSelectedValue.value].coordY;
|
||||
var eovCoord = proj4.Point(x: coordX, y: coordY);
|
||||
var wgsCoord = eovProj.transform(wgsProj, eovCoord);
|
||||
distance.value = calculateDistance(
|
||||
LatLng(gpsLatitude.value, gpsLongitude.value),
|
||||
LatLng(wgsCoord.y, wgsCoord.x));
|
||||
}
|
||||
latDegree.value = ConvertCoordinate.toDegree(gpsLatitude.value);
|
||||
latMin.value = ConvertCoordinate.toMinute(gpsLatitude.value);
|
||||
latSec.value = ConvertCoordinate.toSecond(gpsLatitude.value);
|
||||
longDegree.value = ConvertCoordinate.toDegree(gpsLongitude.value);
|
||||
longMin.value = ConvertCoordinate.toMinute(gpsLongitude.value);
|
||||
longSec.value = ConvertCoordinate.toSecond(gpsLongitude.value);
|
||||
currentLatitude.value = gpsLatitude.value;
|
||||
currentLongitude.value = gpsLongitude.value;
|
||||
_updateCurrentLocationMarker();
|
||||
lastGgaMessage = line;
|
||||
if (ntripIsConnected.value &&
|
||||
(DateTime.now()
|
||||
.difference(lastSendTimeGgaMessage)
|
||||
.inSeconds >=
|
||||
30)) {
|
||||
sendGgaMessage(lastGgaMessage);
|
||||
print("Send GGA message: $lastGgaMessage");
|
||||
ggaSenDataPacketNumber.value++;
|
||||
ggaSendLastTimeStr.value = utcOfPositionFix;
|
||||
lastSendTimeGgaMessage = DateTime.now();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (line.startsWith("\$GNGST") && hasGpsValidData.value) {
|
||||
final sentence = nmeaDecoder.decode(line);
|
||||
if (sentence!.valid && sentence is Gngst) {
|
||||
gpsLatitudeError.value = sentence.latitudeError;
|
||||
gpsLongitudeError.value = sentence.longitudeError;
|
||||
gpsAltitudeError.value = sentence.heightError;
|
||||
}
|
||||
}
|
||||
if (line.startsWith("\$GNRMC") && hasGpsValidData.value) {
|
||||
final sentence = nmeaDecoder.decode(line);
|
||||
if (sentence!.valid && sentence is Gnrmc) {
|
||||
utcDateOfPositionFix = sentence.date;
|
||||
if (utcDateOfPositionFix.isNotEmpty && utcOfPositionFix.isNotEmpty) {
|
||||
gpsDateTime.value = DateTime(
|
||||
2000 +
|
||||
int.parse(
|
||||
"${utcDateOfPositionFix[4]}${utcDateOfPositionFix[5]}"),
|
||||
int.parse(
|
||||
"${utcDateOfPositionFix[2]}${utcDateOfPositionFix[3]}"),
|
||||
int.parse(
|
||||
"${utcDateOfPositionFix[0]}${utcDateOfPositionFix[1]}"),
|
||||
int.parse("${utcOfPositionFix[0]}${utcOfPositionFix[1]}"),
|
||||
int.parse("${utcOfPositionFix[2]}${utcOfPositionFix[3]}"),
|
||||
int.parse("${utcOfPositionFix[4]}${utcOfPositionFix[5]}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String getGpsQualityIndicator({required int quality}) {
|
||||
String qualityStr = "Invalid";
|
||||
switch (quality) {
|
||||
case 0:
|
||||
{
|
||||
qualityStr = "Invalid";
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
qualityStr = "Standard GPS (2D/3D)";
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
qualityStr = "Differential GPS";
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
qualityStr = "RTK Fix";
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
qualityStr = "RTK Float";
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
qualityStr = "Estimated (DR) Fix";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
qualityStr = "Invalid (-1)";
|
||||
}
|
||||
}
|
||||
return qualityStr;
|
||||
}
|
||||
|
||||
void mapZoomOut() {
|
||||
double cLat, cLong;
|
||||
if (currentZoom.value > 0) {
|
||||
currentZoom.value = currentZoom.value - 1;
|
||||
cLat = isMapMoveToCenter.value
|
||||
? currentLatitude.value
|
||||
: mapController.camera.center.latitude;
|
||||
cLong = isMapMoveToCenter.value
|
||||
? currentLongitude.value
|
||||
: mapController.camera.center.longitude;
|
||||
mapController.move(LatLng(cLat, cLong), currentZoom.value);
|
||||
}
|
||||
}
|
||||
|
||||
void mapZoomIn() {
|
||||
double cLat, cLong;
|
||||
if (currentZoom.value < maxZoomValue) {
|
||||
currentZoom.value++;
|
||||
cLat = isMapMoveToCenter.value
|
||||
? currentLatitude.value
|
||||
: mapController.camera.center.latitude;
|
||||
cLong = isMapMoveToCenter.value
|
||||
? currentLongitude.value
|
||||
: mapController.camera.center.longitude;
|
||||
mapController.move(LatLng(cLat, cLong), currentZoom.value);
|
||||
}
|
||||
}
|
||||
|
||||
void _updateCurrentLocationMarker() {
|
||||
currentLocationMarker.clear();
|
||||
currentLocationMarker.add(Marker(
|
||||
point: LatLng(currentLatitude.value, currentLongitude.value),
|
||||
width: 15.0,
|
||||
height: 15.0,
|
||||
child: Container(
|
||||
width: 15.0,
|
||||
height: 15.0,
|
||||
decoration: BoxDecoration(
|
||||
color: getCurrentLocationMarkerColor(quality: gpsQuality.value),
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(width: 1.5, color: Colors.white)),
|
||||
)));
|
||||
if (isMapMoveToCenter.value) {
|
||||
mapController.move(LatLng(currentLatitude.value, currentLongitude.value),
|
||||
currentZoom.value);
|
||||
}
|
||||
}
|
||||
|
||||
Color getCurrentLocationMarkerColor({required int quality}) {
|
||||
Color qualityStr = Colors.black;
|
||||
switch (quality) {
|
||||
case 0:
|
||||
{
|
||||
qualityStr = Colors.black;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
qualityStr = Colors.red;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
qualityStr = Colors.blue;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
qualityStr = Colors.green;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
qualityStr = Colors.orange;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
qualityStr = Colors.yellow;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
qualityStr = Colors.white;
|
||||
}
|
||||
}
|
||||
return qualityStr;
|
||||
}
|
||||
|
||||
void onBottomNavigationBarTap(int index) async {
|
||||
bool noMorePoint = false;
|
||||
print("OnBottomNavTap -> $index");
|
||||
if (index == 0) {
|
||||
pointIdController.text =
|
||||
'${pointsToMeasure[pointsToMeasureSelectedValue.value].id}';
|
||||
// pointIdController.text = pointId.toString();
|
||||
pointDescriptionController.text = "";
|
||||
Get.dialog(
|
||||
AlertDialog(
|
||||
title: const Text("Pont rögzítése"),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(
|
||||
controller: pointIdController,
|
||||
autofocus: true,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(), labelText: 'Azonosító'),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20.0,
|
||||
),
|
||||
TextField(
|
||||
controller: pointDescriptionController,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(), labelText: 'Leírás'),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
TextField(
|
||||
controller: gpsHeightController,
|
||||
autofocus: true,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(), labelText: 'GPS magasság'),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
OutlinedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
minimumSize: const Size(120.0, 40.0)),
|
||||
child: const Text(
|
||||
"Mégsem",
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
),
|
||||
OutlinedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
minimumSize: const Size(120.0, 40.0)),
|
||||
child: const Text(
|
||||
"Ment",
|
||||
style: TextStyle(
|
||||
color: Colors.green, fontWeight: FontWeight.bold),
|
||||
),
|
||||
onPressed: () async {
|
||||
pointId = int.parse(pointIdController.text);
|
||||
pointWithDescriptionList.add(PointWithDescription(
|
||||
pointId,
|
||||
gpsDateTime.value,
|
||||
pointDescriptionController.text,
|
||||
eov.value.Y,
|
||||
eov.value.X,
|
||||
gpsLatitude.value,
|
||||
gpsLongitude.value,
|
||||
max(gpsLatitudeError.value, gpsLongitudeError.value),
|
||||
gpsAltitudeError.value));
|
||||
print(
|
||||
"pointWithDescriptionList -> ${pointWithDescriptionList.length}");
|
||||
|
||||
pointNotesMarker.add(Marker(
|
||||
point: LatLng(gpsLatitude.value, gpsLongitude.value),
|
||||
width: 15.0,
|
||||
height: 15.0,
|
||||
child: Container(
|
||||
width: 15.0,
|
||||
height: 15.0,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.amber[700],
|
||||
shape: BoxShape.circle,
|
||||
border:
|
||||
Border.all(width: 1.0, color: Colors.black)),
|
||||
)));
|
||||
await dataFile.writeAsString(
|
||||
"$pointId;$gpsDateTime;${pointDescriptionController.text};${formatEovForFile.format(eov.value.Y)};${formatEovForFile.format(eov.value.X)};$gpsLatitude;$gpsLongitude;$gpsAltitude;${max(gpsLatitudeError.value, gpsLongitudeError.value)};$gpsAltitudeError;${gpsHeightController.text}\r\n",
|
||||
mode: FileMode.append);
|
||||
|
||||
_measuredPoints.add({
|
||||
"id": pointId,
|
||||
"dateAndTime": gpsDateTime.value,
|
||||
"latitude": gpsLatitude.value,
|
||||
"longitude": gpsLongitude.value,
|
||||
"altitude": gpsAltitude.value,
|
||||
"eovY": formatEovForFile.format(eov.value.Y),
|
||||
"eovX": formatEovForFile.format(eov.value.X),
|
||||
"description": pointDescriptionController.text,
|
||||
"horizontalError":
|
||||
max(gpsLatitudeError.value, gpsLongitudeError.value),
|
||||
"verticalError": gpsAltitudeError.value,
|
||||
"gpsHeight": gpsHeightController.text
|
||||
});
|
||||
|
||||
if (pointMeasuringDirectionForward.isTrue) {
|
||||
if (pointsToMeasureSelectedValue.value <
|
||||
pointsToMeasure.length - 1) {
|
||||
pointId++;
|
||||
pointsToMeasureSelectedValue.value += 1;
|
||||
noMorePoint = false;
|
||||
} else {
|
||||
noMorePoint = true;
|
||||
// Get.snackbar("Információ", "Nincs több bemérendő pont.",
|
||||
// colorText: Colors.white,
|
||||
// backgroundColor: Colors.lightBlue);
|
||||
ScaffoldMessenger.of(Get.context!).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Nincs több bemérendő pont.')));
|
||||
}
|
||||
} else {
|
||||
if (pointsToMeasureSelectedValue.value > 0) {
|
||||
pointId--;
|
||||
pointsToMeasureSelectedValue.value -= 1;
|
||||
noMorePoint = false;
|
||||
} else {
|
||||
noMorePoint = true;
|
||||
ScaffoldMessenger.of(Get.context!).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Nincs több bemérendő pont.')));
|
||||
}
|
||||
}
|
||||
|
||||
Get.back();
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
barrierDismissible: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void sendGgaMessage(String ggaMessage) {
|
||||
if (ntripIsConnected.value && ggaMessage.isNotEmpty) {
|
||||
socket.add(_convertStringToUint8List("$ggaMessage\r\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void setIsMapMoveToCenter() {
|
||||
isMapMoveToCenter.value = !isMapMoveToCenter.value;
|
||||
// onBottomNavigationBarTap(0);
|
||||
}
|
||||
|
||||
void ReadPointsFromFile() async {
|
||||
File? file;
|
||||
FilePickerResult? result = await FilePicker.platform.pickFiles();
|
||||
|
||||
if (result != null) {
|
||||
file = File(result.files.single.path!);
|
||||
} else {
|
||||
print("No file selected");
|
||||
}
|
||||
if (await file!.exists()) {
|
||||
pointsToMeasure.clear();
|
||||
final content = await file.readAsLines();
|
||||
print('Length: -> ${content.length}');
|
||||
|
||||
for (final (index, item) in content.indexed) {
|
||||
if (index == 0) {
|
||||
continue;
|
||||
}
|
||||
var items = item.split(";");
|
||||
if (items.length >= 3) {
|
||||
var id = int.tryParse(items[0]);
|
||||
var coordX = double.tryParse(items[1].replaceAll(',', '.'));
|
||||
var coordY = double.tryParse(items[2].replaceAll(',', '.'));
|
||||
|
||||
if (id != null && coordX != null && coordY != null) {
|
||||
pointsToMeasure
|
||||
.add(PointToMeasure(id: id, coordX: coordX, coordY: coordY));
|
||||
|
||||
var eovCoord = proj4.Point(x: coordX, y: coordY);
|
||||
var wgsCoord = eovProj.transform(wgsProj, eovCoord);
|
||||
|
||||
print("Lat -> ${wgsCoord.x}, Long -> ${wgsCoord.y}");
|
||||
|
||||
pointsToMeasureMarker.add(Marker(
|
||||
point: LatLng(wgsCoord.y, wgsCoord.x),
|
||||
width: 15.0,
|
||||
height: 15.0,
|
||||
child: Container(
|
||||
width: 15.0,
|
||||
height: 15.0,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.purple,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(width: 1.0, color: Colors.black)),
|
||||
)));
|
||||
|
||||
pointsToMeasureLabel.add(PolyWidget(
|
||||
center: LatLng(wgsCoord.y + 0.0000075, wgsCoord.x + 0.0000075),
|
||||
widthInMeters: 3,
|
||||
heightInMeters: 3,
|
||||
// constraints: const BoxConstraints(
|
||||
// minWidth: 250,
|
||||
// maxWidth: 350,
|
||||
// ),
|
||||
child: FittedBox(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Text(
|
||||
' $id ',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.yellow,
|
||||
fontSize: 12.0),
|
||||
),
|
||||
),
|
||||
)));
|
||||
|
||||
pointsToMeasureDropDownMenuItem.add(DropdownMenuItem<int>(
|
||||
value: index - 1,
|
||||
child: Text('$id'),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
pointsToMeasureSelectedValue.value = 0;
|
||||
print('Converted points number -> ${pointsToMeasure.length}');
|
||||
}
|
||||
}
|
||||
|
||||
void pointsToMeasureSelectedValueChanged(int value) {
|
||||
pointsToMeasureSelectedValue.value = value;
|
||||
print('Selected point -> ${pointsToMeasureSelectedValue.value}');
|
||||
}
|
||||
|
||||
double calculateDistance(LatLng start, LatLng end) {
|
||||
const double earthRadius = 6371.0; // Radius of the Earth in kilometers
|
||||
|
||||
// Convert coordinates to radians
|
||||
final double lat1 = start.latitude * (pi / 180.0);
|
||||
final double lon1 = start.longitude * (pi / 180.0);
|
||||
final double lat2 = end.latitude * (pi / 180.0);
|
||||
final double lon2 = end.longitude * (pi / 180.0);
|
||||
|
||||
// Calculate the differences between the coordinates
|
||||
final double dLat = lat2 - lat1;
|
||||
final double dLon = lon2 - lon1;
|
||||
|
||||
// Apply the Haversine formula
|
||||
final double a = sin(dLat / 2) * sin(dLat / 2) +
|
||||
cos(lat1) * cos(lat2) * sin(dLon / 2) * sin(dLon / 2);
|
||||
final double c = 2 * atan2(sqrt(a), sqrt(1 - a));
|
||||
final double distance = earthRadius * c;
|
||||
|
||||
return distance; // Distance in kilometers, add "*1000" to get meters
|
||||
}
|
||||
|
||||
void addMeasuredPoint() {
|
||||
_measuredPoints.add({"id": 4001, "latitude": 46.3455, "longitude": 19.652});
|
||||
}
|
||||
|
||||
void showAddPointDialog() {
|
||||
onBottomNavigationBarTap(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/map/presentation/controllers/map_controller.dart';
|
||||
|
||||
class MapAddPointDialog extends GetView<MapViewController> {
|
||||
const MapAddPointDialog({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(
|
||||
controller: controller.pointIdController,
|
||||
autofocus: true,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(), labelText: 'Azonosító'),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20.0,
|
||||
),
|
||||
TextField(
|
||||
controller: controller.pointDescriptionController,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(), labelText: 'Leírás'),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
OutlinedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
minimumSize: const Size(120.0, 40.0)),
|
||||
child: const Text(
|
||||
"Mégsem",
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
),
|
||||
OutlinedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
minimumSize: const Size(120.0, 40.0)),
|
||||
child: const Text(
|
||||
"Ment",
|
||||
style: TextStyle(
|
||||
color: Colors.green, fontWeight: FontWeight.bold),
|
||||
),
|
||||
onPressed: () async {
|
||||
// pointId = int.parse(pointIdController.text);
|
||||
// pointWithDescriptionList.add(PointWithDescription(
|
||||
// pointId,
|
||||
// gpsDateTime.value,
|
||||
// pointDescriptionController.text,
|
||||
// eov.value.Y,
|
||||
// eov.value.X,
|
||||
// gpsLatitude.value,
|
||||
// gpsLongitude.value,
|
||||
// max(gpsLatitudeError.value, gpsLongitudeError.value),
|
||||
// gpsAltitudeError.value));
|
||||
// print(
|
||||
// "pointWithDescriptionList -> ${pointWithDescriptionList.length}");
|
||||
// pointNotesMarker.add(Marker(
|
||||
// point: LatLng(gpsLatitude.value, gpsLongitude.value),
|
||||
// width: 15.0,
|
||||
// height: 15.0,
|
||||
// builder: (ctx) => Container(
|
||||
// width: 15.0,
|
||||
// height: 15.0,
|
||||
// decoration: BoxDecoration(
|
||||
// color: Colors.purple,
|
||||
// shape: BoxShape.circle,
|
||||
// border: Border.all(
|
||||
// width: 1.0, color: Colors.black)),
|
||||
// )));
|
||||
// await dataFile.writeAsString(
|
||||
// "$pointId;$gpsDateTime;${pointDescriptionController.text};${formatEovForFile.format(eov.value.Y)};${formatEovForFile.format(eov.value.X)};$gpsLatitude;$gpsLongitude;$gpsAltitude;${max(gpsLatitudeError.value, gpsLongitudeError.value)};$gpsAltitudeError\r\n",
|
||||
// mode: FileMode.append);
|
||||
|
||||
// pointId++;
|
||||
|
||||
Get.back();
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,458 @@
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map_polywidget/flutter_map_polywidget.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:rive/rive.dart';
|
||||
import 'package:terepi_seged/pages/map/presentation/controllers/map_controller.dart';
|
||||
import 'package:terepi_seged/pages/map/presentation/views/settings_dialog.dart';
|
||||
import 'package:terepi_seged/utils/rive_utils.dart';
|
||||
|
||||
import 'map_add_point_dialog.dart';
|
||||
|
||||
class MapView extends GetView<MapViewController> {
|
||||
const MapView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
late SMIBool gpsTrigger;
|
||||
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
extendBody: true,
|
||||
appBar: AppBar(
|
||||
title: const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Térkép'),
|
||||
Text(
|
||||
"Budapest",
|
||||
style: TextStyle(fontSize: 12.0),
|
||||
)
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 20.0),
|
||||
child: Obx(
|
||||
() => GestureDetector(
|
||||
onTap: () {
|
||||
if (controller.gpsIsConnected.value) {
|
||||
controller.disconnectFromGps();
|
||||
} else {
|
||||
controller.connectToGps();
|
||||
}
|
||||
},
|
||||
child: Icon(Icons.gps_fixed,
|
||||
size: 26.0,
|
||||
color: controller.gpsIsConnected.value
|
||||
? Colors.green
|
||||
: Colors.red),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 20.0),
|
||||
child: Obx(
|
||||
() => GestureDetector(
|
||||
onTap: () {
|
||||
if (controller.ntripIsConnected.value) {
|
||||
controller.disconnectFromNtripServer();
|
||||
} else {
|
||||
controller.connectToNtripServer();
|
||||
}
|
||||
},
|
||||
child: Icon(
|
||||
Icons.assistant,
|
||||
size: 26.0,
|
||||
color: controller.ntripIsConnected.value
|
||||
? Colors.green
|
||||
: Colors.red,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 20.0),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
controller.ReadPointsFromFile();
|
||||
},
|
||||
child:
|
||||
const Icon(Icons.file_open, size: 26.0, color: Colors.blue),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 20.0),
|
||||
child: GestureDetector(
|
||||
onTap: () => Get.to(() => SettingsDialog(),
|
||||
transition: Transition.downToUp),
|
||||
child: const Icon(
|
||||
Icons.more_vert,
|
||||
size: 26.0,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
Obx(
|
||||
() => controller.gpsIsConnected.value
|
||||
? Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: 170.0,
|
||||
// height: 160.0,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 2.0,
|
||||
color: const Color.fromARGB(
|
||||
130, 255, 255, 255)),
|
||||
color:
|
||||
const Color.fromARGB(130, 255, 255, 255)),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"${controller.gpsDateTime} (UTC)",
|
||||
style: const TextStyle(fontSize: 10.0),
|
||||
),
|
||||
const Divider(
|
||||
height: 5.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
Text(
|
||||
"EovX: ${controller.formatEov.format(controller.eov.value.Y)}"),
|
||||
Text(
|
||||
"EovY: ${controller.formatEov.format(controller.eov.value.X)}"),
|
||||
Text("Alt: ${controller.gpsAltitude} (m)"),
|
||||
const Divider(
|
||||
height: 5.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
Text(
|
||||
"Hor. error: ${max(controller.gpsLatitudeError.value, controller.gpsLongitudeError.value)} (m)",
|
||||
style: const TextStyle(fontSize: 14.0),
|
||||
),
|
||||
Text(
|
||||
"Vert. error: ${controller.gpsAltitudeError} (m)",
|
||||
style: const TextStyle(fontSize: 14.0),
|
||||
),
|
||||
const Divider(
|
||||
height: 5.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
Text(
|
||||
"GPS quality -> ${controller.getGpsQualityIndicator(quality: controller.gpsQuality.value)} ",
|
||||
style: const TextStyle(fontSize: 8.0),
|
||||
),
|
||||
controller.ntripIsConnected.value
|
||||
? Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Divider(
|
||||
height: 5.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
Text(
|
||||
"Ntrip ${controller.ntripReceivedData} byte(s) (${controller.ntripDataPacketNumbers})",
|
||||
style:
|
||||
const TextStyle(fontSize: 10.0),
|
||||
),
|
||||
Text(
|
||||
"GGA last send: ${controller.ggaSendLastTimeStr} (${controller.ggaSenDataPacketNumber})",
|
||||
style:
|
||||
const TextStyle(fontSize: 10.0),
|
||||
),
|
||||
],
|
||||
)
|
||||
: const SizedBox(
|
||||
width: 0.0,
|
||||
height: 0.0,
|
||||
)
|
||||
],
|
||||
)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
DropdownButton(
|
||||
onChanged: (int? newValue) {
|
||||
controller
|
||||
.pointsToMeasureSelectedValueChanged(
|
||||
newValue!);
|
||||
},
|
||||
items:
|
||||
controller.pointsToMeasureDropDownMenuItem,
|
||||
value: controller
|
||||
.pointsToMeasureSelectedValue.value,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
FittedBox(
|
||||
child: Text(
|
||||
'Távolság: ${(controller.distance * 1000).toStringAsFixed(3)} m',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 12.0),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
),
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
Obx(
|
||||
() => controller.mapIsInitialized.value
|
||||
? FlutterMap(
|
||||
mapController: controller.mapController,
|
||||
options: MapOptions(
|
||||
center: LatLng(controller.currentLatitude.value,
|
||||
controller.currentLongitude.value),
|
||||
maxZoom: 25,
|
||||
zoom: controller.currentZoom.value,
|
||||
),
|
||||
children: [
|
||||
TileLayer(
|
||||
urlTemplate:
|
||||
'http://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}',
|
||||
subdomains: const ['mt0', 'mt1', 'mt2', 'mt3'],
|
||||
maxNativeZoom: 18,
|
||||
// urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
// userAgentPackageName: 'hu.app_dev.terepi_seged',
|
||||
),
|
||||
MarkerLayer(
|
||||
markers: controller.pointNotesMarker,
|
||||
),
|
||||
MarkerLayer(
|
||||
markers: controller.currentLocationMarker),
|
||||
MarkerLayer(markers: controller.parser.markers),
|
||||
MarkerLayer(
|
||||
markers: controller.pointsToMeasureMarker),
|
||||
// PolylineLayer(
|
||||
// polylines: controller.parser.polylines),
|
||||
PolyWidgetLayer(
|
||||
polyWidgets: controller.pointsToMeasureLabel)
|
||||
],
|
||||
)
|
||||
: const Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
// Obx(
|
||||
// () => controller.gpsIsConnected.value
|
||||
// ? Positioned(
|
||||
// left: 4.0,
|
||||
// top: 4.0,
|
||||
// child: Container(
|
||||
// width: 170.0,
|
||||
// // height: 160.0,
|
||||
// decoration: BoxDecoration(
|
||||
// border: Border.all(
|
||||
// width: 2.0,
|
||||
// color: const Color.fromARGB(
|
||||
// 130, 255, 255, 255)),
|
||||
// color:
|
||||
// const Color.fromARGB(130, 255, 255, 255)),
|
||||
// child: Column(
|
||||
// mainAxisAlignment: MainAxisAlignment.start,
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// Text(
|
||||
// "${controller.gpsDateTime} (UTC)",
|
||||
// style: const TextStyle(fontSize: 10.0),
|
||||
// ),
|
||||
// const Divider(
|
||||
// height: 5.0,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// Text(
|
||||
// "EovX: ${controller.formatEov.format(controller.eov.value.Y)}"),
|
||||
// Text(
|
||||
// "EovY: ${controller.formatEov.format(controller.eov.value.X)}"),
|
||||
// Text("Alt: ${controller.gpsAltitude} (m)"),
|
||||
// const Divider(
|
||||
// height: 5.0,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// Text(
|
||||
// "Hor. error: ${max(controller.gpsLatitudeError.value, controller.gpsLongitudeError.value)} (m)",
|
||||
// style: const TextStyle(fontSize: 14.0),
|
||||
// ),
|
||||
// Text(
|
||||
// "Vert. error: ${controller.gpsAltitudeError} (m)",
|
||||
// style: const TextStyle(fontSize: 14.0),
|
||||
// ),
|
||||
// const Divider(
|
||||
// height: 5.0,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// Text(
|
||||
// "GPS quality -> ${controller.getGpsQualityIndicator(quality: controller.gpsQuality.value)} ",
|
||||
// style: const TextStyle(fontSize: 8.0),
|
||||
// ),
|
||||
// controller.ntripIsConnected.value
|
||||
// ? Column(
|
||||
// crossAxisAlignment:
|
||||
// CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// const Divider(
|
||||
// height: 5.0,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// Text(
|
||||
// "Ntrip ${controller.ntripReceivedData} byte(s) (${controller.ntripDataPacketNumbers})",
|
||||
// style: const TextStyle(
|
||||
// fontSize: 10.0),
|
||||
// ),
|
||||
// Text(
|
||||
// "GGA last send: ${controller.ggaSendLastTimeStr} (${controller.ggaSenDataPacketNumber})",
|
||||
// style: const TextStyle(
|
||||
// fontSize: 10.0),
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
// : const SizedBox(
|
||||
// width: 0.0,
|
||||
// height: 0.0,
|
||||
// )
|
||||
// ],
|
||||
// )),
|
||||
// )
|
||||
// : const Positioned(
|
||||
// child: SizedBox(
|
||||
// width: 0.0,
|
||||
// height: 0.0,
|
||||
// )),
|
||||
// )
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// bottomNavigationBar: Container(
|
||||
// padding: const EdgeInsets.all(12),
|
||||
// margin: const EdgeInsets.symmetric(horizontal: 24),
|
||||
// decoration: BoxDecoration(
|
||||
// color: Colors.black.withOpacity(0.5),
|
||||
// borderRadius: const BorderRadius.all(Radius.circular(24))),
|
||||
// child: Row(
|
||||
// children: [
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// gpsTrigger.change(true);
|
||||
// Future.delayed(const Duration(seconds: 1), () {
|
||||
// gpsTrigger.change(false);
|
||||
// });
|
||||
// // controller.onBottomNavigationBarTap(0);
|
||||
// Get.to(() => const MapAddPointDialog(),
|
||||
// fullscreenDialog: true,
|
||||
// transition: Transition.downToUp,
|
||||
// duration: const Duration(milliseconds: 600));
|
||||
// },
|
||||
// child: SizedBox(
|
||||
// height: 36,
|
||||
// width: 36,
|
||||
// child: RiveAnimation.asset(
|
||||
// "assets/RiveAssets/travel_icons_pack.riv",
|
||||
// artboard: "GPS", onInit: (artboard) {
|
||||
// StateMachineController controllerRive =
|
||||
// RiveUtils.getRiveController(artboard,
|
||||
// stateMachineName: "gps_interactivity");
|
||||
// gpsTrigger = controllerRive.findSMI("active") as SMIBool;
|
||||
// }),
|
||||
// ),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.startFloat,
|
||||
floatingActionButton: Wrap(
|
||||
direction: Axis.horizontal,
|
||||
children: [
|
||||
FloatingActionButton(
|
||||
onPressed: () {
|
||||
controller.mapZoomOut();
|
||||
},
|
||||
heroTag: 'ZoomOut',
|
||||
tooltip: 'Zoom out',
|
||||
child: const Icon(Icons.remove_circle_outline_rounded),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
FloatingActionButton(
|
||||
onPressed: () {
|
||||
controller.mapZoomIn();
|
||||
},
|
||||
heroTag: 'ZoomIn',
|
||||
tooltip: 'Zoom in',
|
||||
child: const Icon(Icons.add_circle_outline_rounded),
|
||||
),
|
||||
const SizedBox(width: 15.0),
|
||||
FloatingActionButton(
|
||||
onPressed: () {
|
||||
// controller.isMapMoveToCenter();
|
||||
controller.setIsMapMoveToCenter();
|
||||
},
|
||||
heroTag: 'Center map',
|
||||
tooltip: 'Center map',
|
||||
child: Obx(
|
||||
() => Icon(Icons.center_focus_strong,
|
||||
color: controller.isMapMoveToCenter.value
|
||||
? Colors.green
|
||||
: Colors.red),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 15.0,
|
||||
),
|
||||
FloatingActionButton(
|
||||
onPressed: () {
|
||||
// controller.addMeasuredPoint();
|
||||
// controller.onBottomNavigationBarTap(0);
|
||||
controller.showAddPointDialog();
|
||||
},
|
||||
heroTag: 'Pont bemérése',
|
||||
tooltip: 'Pont bemérése',
|
||||
child: const Icon(Icons.flag_sharp),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 15.0,
|
||||
),
|
||||
FloatingActionButton(
|
||||
onPressed: () {
|
||||
// controller.isMapMoveToCenter();
|
||||
// controller.addMeasuredPoint();
|
||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||
content: Text(
|
||||
"Fejlesztlés alatt",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
backgroundColor: Colors.black54,
|
||||
));
|
||||
},
|
||||
heroTag: 'Database test',
|
||||
tooltip: 'Pont bemérése',
|
||||
child: const Icon(Icons.dataset),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/map/presentation/controllers/map_controller.dart';
|
||||
|
||||
class SettingsDialog extends StatelessWidget {
|
||||
final controller = Get.find<MapViewController>();
|
||||
SettingsDialog({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: ListView(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
icon: const Icon(Icons.close)),
|
||||
TextButton(
|
||||
style: ButtonStyle(
|
||||
overlayColor:
|
||||
MaterialStateProperty.all(Colors.transparent)),
|
||||
onPressed: () {},
|
||||
child: const Text(
|
||||
'Bezár',
|
||||
style: TextStyle(color: Colors.blue, fontSize: 14.0),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 40.0),
|
||||
child: Text(
|
||||
'Beállítások',
|
||||
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 40.0),
|
||||
child: Text(
|
||||
'GPS vevő',
|
||||
style: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
Obx(() => Column(children: [
|
||||
RadioListTile(
|
||||
title: Text('TiGNSS Rover-FF4E'),
|
||||
value: '98:CD:AC:62:FF:4E',
|
||||
groupValue: controller.gpsAddress.value,
|
||||
onChanged: (value) {
|
||||
controller.gpsAddress.value = value!;
|
||||
}),
|
||||
RadioListTile(
|
||||
title: Text('TiGNSS Rover-8BB2'),
|
||||
value: 'E8:31:CD:14:8B:B2',
|
||||
groupValue: controller.gpsAddress.value,
|
||||
onChanged: (value) {
|
||||
controller.gpsAddress.value = value!;
|
||||
;
|
||||
}),
|
||||
RadioListTile(
|
||||
title: Text('TiGNSS Rover-FF36'),
|
||||
value: '98:CD:AC:62:FF:36',
|
||||
groupValue: controller.gpsAddress.value,
|
||||
onChanged: (value) {
|
||||
controller.gpsAddress.value = value!;
|
||||
})
|
||||
])),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Divider(
|
||||
height: 5,
|
||||
),
|
||||
),
|
||||
// const SizedBox(height: 5),
|
||||
// const Padding(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 40.0),
|
||||
// child: Text(
|
||||
// 'Bemért pont azonosítója:',
|
||||
// style: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500),
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 4),
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 40),
|
||||
// child: Row(
|
||||
// children: [
|
||||
// Flexible(
|
||||
// child: TextField(
|
||||
// controller: controller.pointPrefixController,
|
||||
// decoration: const InputDecoration(
|
||||
// border: OutlineInputBorder(), labelText: 'Előtag'),
|
||||
// ),
|
||||
// ),
|
||||
// const Padding(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||
// child: Text(
|
||||
// 'Eredeti azonosító',
|
||||
// style: TextStyle(fontSize: 12.0),
|
||||
// ),
|
||||
// ),
|
||||
// Flexible(
|
||||
// child: TextField(
|
||||
// controller: controller.pointPostfixController,
|
||||
// decoration: const InputDecoration(
|
||||
// border: OutlineInputBorder(), labelText: 'Utótag'),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
const SizedBox(height: 5),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: Text(
|
||||
'Mérés iránya:',
|
||||
style: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
Obx(
|
||||
() => Column(children: [
|
||||
RadioListTile<bool>(
|
||||
title: Text('Növekvő'),
|
||||
value: true,
|
||||
groupValue: controller.pointMeasuringDirectionForward.value,
|
||||
onChanged: (value) {
|
||||
controller.pointMeasuringDirectionForward.value = value!;
|
||||
}),
|
||||
RadioListTile<bool>(
|
||||
title: Text('Csökkenő'),
|
||||
value: false,
|
||||
groupValue: controller.pointMeasuringDirectionForward.value,
|
||||
onChanged: (value) {
|
||||
controller.pointMeasuringDirectionForward.value = value!;
|
||||
})
|
||||
]),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Divider(
|
||||
height: 5,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: Text(
|
||||
'Kitűzött pont azonostója:',
|
||||
style: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
child: SizedBox(
|
||||
height: 32,
|
||||
width: double.infinity,
|
||||
child: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: TextField(
|
||||
controller: controller.pointPrefixController,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(), labelText: 'Előtag'),
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Text(
|
||||
'Eredeti azonosító',
|
||||
style: TextStyle(fontSize: 12.0),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: TextField(
|
||||
controller: controller.pointPostfixController,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(), labelText: 'Utótag'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 20, top: 8),
|
||||
child: Text(
|
||||
'Például: előtag: 6, utótag: -bp, eredeti azonositó: 1002 -> 61002-bp',
|
||||
style: TextStyle(fontSize: 10, fontWeight: FontWeight.w400))),
|
||||
const SizedBox(height: 15),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Divider(
|
||||
height: 5,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: Text(
|
||||
'Ntrip szolgáltatás:',
|
||||
style: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: Column(children: [
|
||||
SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
controller: controller.ntripUsernameController,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
labelText: 'Felhasználónév',
|
||||
icon: Icon(Icons.account_circle_rounded)),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
obscureText: true,
|
||||
enableSuggestions: false,
|
||||
autocorrect: false,
|
||||
controller: controller.ntripPasswordController,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
labelText: 'Jelszó',
|
||||
icon: Icon(
|
||||
Icons.lock,
|
||||
)),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20)
|
||||
]),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/map_test/presentation/controllers/map_test_controller.dart';
|
||||
|
||||
class MapTestBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => MapTestController());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:location/location.dart';
|
||||
import 'package:syncfusion_flutter_maps/maps.dart';
|
||||
|
||||
class MapTestController extends GetxController {
|
||||
late MapShapeSource mapSource;
|
||||
late MapShapeSource kozigSource;
|
||||
late MapZoomPanBehavior zoomPanBehavior;
|
||||
late MapTileLayerController mapTileLayerController;
|
||||
|
||||
late List<MapLatLng> line1, line2, line3;
|
||||
late List<List<MapLatLng>> lines1, lines2, lines3;
|
||||
late List<MapModel> mapModel = [];
|
||||
|
||||
late StreamSubscription<LocationData> locationSubscription;
|
||||
bool locationSubscriptionIsInitialized = false;
|
||||
Location location = Location();
|
||||
RxDouble currentLongitude = 18.122495576634044.obs;
|
||||
RxDouble currentLatitude = 46.328746702592106.obs;
|
||||
RxBool isInitialized = false.obs;
|
||||
|
||||
@override
|
||||
void onInit() async {
|
||||
mapTileLayerController = MapTileLayerController();
|
||||
bool res = await loadMapData();
|
||||
|
||||
location.changeSettings(
|
||||
accuracy: LocationAccuracy.high, interval: 500, distanceFilter: 1);
|
||||
|
||||
line1 = const <MapLatLng>[
|
||||
MapLatLng(46.409474083913345, 18.196055479431202),
|
||||
MapLatLng(46.40229074049568, 18.184834829804377),
|
||||
MapLatLng(46.400881093344097, 18.183525800449701),
|
||||
MapLatLng(46.392903944366708, 18.177253122976378),
|
||||
MapLatLng(46.384773311328807, 18.170585406188426),
|
||||
MapLatLng(46.382049391318191, 18.168012348371033),
|
||||
MapLatLng(46.381677738114753, 18.167665852333496),
|
||||
MapLatLng(46.381161940383038, 18.167149737333396),
|
||||
MapLatLng(46.377534073316291, 18.164141681038203),
|
||||
MapLatLng(46.374368645392636, 18.161698675385864),
|
||||
MapLatLng(46.370683914933664, 18.158587091204133),
|
||||
MapLatLng(46.3640763356468, 18.153155234991335),
|
||||
MapLatLng(46.363576961214015, 18.152317669751312),
|
||||
MapLatLng(46.35389201272092, 18.13590711186691),
|
||||
MapLatLng(46.352978857192532, 18.133309083714881),
|
||||
MapLatLng(46.35137058576526, 18.13098235253349),
|
||||
MapLatLng(46.348440208996635, 18.126684238252697),
|
||||
MapLatLng(46.347130535026032, 18.123117395006844),
|
||||
MapLatLng(46.34706818966626, 18.122931136322965),
|
||||
MapLatLng(46.346565571573841, 18.122161191477915),
|
||||
MapLatLng(46.346370011622788, 18.121391157301662),
|
||||
MapLatLng(46.342636923837361, 18.112691291995962),
|
||||
MapLatLng(46.342389315173889, 18.111910189208963),
|
||||
MapLatLng(46.333172947557394, 18.099415040392927),
|
||||
MapLatLng(46.32863226668006, 18.087695666266029),
|
||||
MapLatLng(46.325737435025978, 18.08355812652276),
|
||||
// MapLatLng(46.322053106393668, 18.078583447909164),
|
||||
// MapLatLng(46.318345777758296, 18.075366997618815),
|
||||
// MapLatLng(46.317198167430817, 18.074782985031753),
|
||||
// MapLatLng(46.316022015155262, 18.07310019901135),
|
||||
// MapLatLng(46.314147548726261, 18.072144612154844),
|
||||
// MapLatLng(46.312510626772578, 18.071178953163265),
|
||||
// MapLatLng(46.310758970899364, 18.068863947464287),
|
||||
// MapLatLng(46.308993975939856, 18.065995601793436),
|
||||
// MapLatLng(46.302099673468611, 18.060496509299735),
|
||||
// MapLatLng(46.299097775521432, 18.05627769200369),
|
||||
// MapLatLng(46.295182331629846, 18.051900556314489),
|
||||
// MapLatLng(46.292525209632785, 18.048285539930436),
|
||||
// MapLatLng(46.290524900577878, 18.045515378447099)
|
||||
];
|
||||
|
||||
line3 = const <MapLatLng>[
|
||||
MapLatLng(46.325737435025978, 18.08355812652276),
|
||||
MapLatLng(46.322053106393668, 18.078583447909164),
|
||||
MapLatLng(46.318345777758296, 18.075366997618815),
|
||||
MapLatLng(46.317198167430817, 18.074782985031753),
|
||||
MapLatLng(46.316022015155262, 18.07310019901135),
|
||||
MapLatLng(46.314147548726261, 18.072144612154844),
|
||||
MapLatLng(46.312510626772578, 18.071178953163265),
|
||||
MapLatLng(46.310758970899364, 18.068863947464287),
|
||||
MapLatLng(46.308993975939856, 18.065995601793436),
|
||||
MapLatLng(46.302099673468611, 18.060496509299735),
|
||||
MapLatLng(46.299097775521432, 18.05627769200369),
|
||||
MapLatLng(46.295182331629846, 18.051900556314489),
|
||||
MapLatLng(46.292525209632785, 18.048285539930436),
|
||||
MapLatLng(46.290524900577878, 18.045515378447099)
|
||||
];
|
||||
|
||||
line2 = const <MapLatLng>[
|
||||
// MapLatLng(46.260064352706863, 18.116797380886084),
|
||||
MapLatLng(46.251888084511876, 18.116765702743511),
|
||||
MapLatLng(46.276731538707907, 18.118312495916047),
|
||||
MapLatLng(46.290630785869595, 18.121715933401102),
|
||||
MapLatLng(46.291602112755918, 18.121615413423505),
|
||||
MapLatLng(46.293861019929999, 18.121966080774971),
|
||||
MapLatLng(46.306808758830037, 18.120536071329884),
|
||||
MapLatLng(46.307565036417657, 18.120339010103002),
|
||||
MapLatLng(46.313074623341073, 18.12005586208279),
|
||||
MapLatLng(46.315292570695746, 18.120136355999676),
|
||||
MapLatLng(46.317610563278862, 18.120225447918834),
|
||||
MapLatLng(46.31852533235655, 18.120312832087762),
|
||||
MapLatLng(46.324753378018201, 18.120473866804605),
|
||||
MapLatLng(46.334486981796822, 18.117343038689867),
|
||||
MapLatLng(46.335047155775996, 18.117367081901961),
|
||||
MapLatLng(46.337466485256385, 18.116990955631348),
|
||||
MapLatLng(46.340277266846968, 18.116562251592601),
|
||||
MapLatLng(46.343322881556979, 18.116268008370902),
|
||||
MapLatLng(46.347183527547493, 18.113215711471319),
|
||||
MapLatLng(46.347908214739213, 18.112661806065514),
|
||||
MapLatLng(46.348086908069178, 18.112669488541766),
|
||||
MapLatLng(46.348833657599236, 18.113161876278717),
|
||||
MapLatLng(46.35355966637772, 18.112136546361285),
|
||||
MapLatLng(46.357138992408714, 18.111476412678716)
|
||||
];
|
||||
|
||||
lines2 = [line2];
|
||||
lines3 = [line3];
|
||||
lines1 = [line1];
|
||||
|
||||
await _getInitialLocation();
|
||||
|
||||
mapSource = MapShapeSource.asset(
|
||||
'assets/Files/erintett_telkek_0613.geojson',
|
||||
shapeDataField: "id1",
|
||||
dataCount: mapModel.length,
|
||||
primaryValueMapper: (index) => mapModel[index].id!,
|
||||
dataLabelMapper: (index) => mapModel[index].hrsz!,
|
||||
shapeColorValueMapper: (index) => mapModel[index].color!,
|
||||
);
|
||||
kozigSource = const MapShapeSource.asset(
|
||||
'assets/Files/kozig_hatar.geojson',
|
||||
shapeDataField: "Telepules",
|
||||
);
|
||||
|
||||
zoomPanBehavior = MapZoomPanBehavior(
|
||||
minZoomLevel: 1,
|
||||
maxZoomLevel: 25,
|
||||
zoomLevel: 15,
|
||||
// focalLatLng: const MapLatLng(46.328746702592106, 18.122495576634044));
|
||||
focalLatLng: MapLatLng(currentLatitude.value, currentLongitude.value));
|
||||
|
||||
_listenLocation();
|
||||
|
||||
super.onInit();
|
||||
isInitialized.value = true;
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
if (locationSubscriptionIsInitialized) {
|
||||
locationSubscription.cancel();
|
||||
}
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
Future<void> _getInitialLocation() async {
|
||||
bool servicedEnabled;
|
||||
PermissionStatus permissionGranted;
|
||||
LocationData locationData;
|
||||
Location location = Location();
|
||||
|
||||
servicedEnabled = await location.serviceEnabled();
|
||||
if (!servicedEnabled) {
|
||||
servicedEnabled = await location.requestService();
|
||||
if (!servicedEnabled) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
permissionGranted = await location.hasPermission();
|
||||
if (permissionGranted == PermissionStatus.denied) {
|
||||
permissionGranted = await location.requestPermission();
|
||||
if (permissionGranted != PermissionStatus.granted) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
locationData = await location.getLocation();
|
||||
currentLatitude.value = locationData.latitude ?? 0.0;
|
||||
currentLongitude.value = locationData.longitude ?? 0.0;
|
||||
}
|
||||
|
||||
Future<void> _listenLocation() async {
|
||||
locationSubscription =
|
||||
location.onLocationChanged.handleError((dynamic err) {
|
||||
locationSubscription.cancel();
|
||||
}).listen((LocationData currentLocation) {
|
||||
currentLatitude.value = currentLocation.latitude!;
|
||||
currentLongitude.value = currentLocation.longitude!;
|
||||
locationSubscriptionIsInitialized = true;
|
||||
log('x: ${currentLatitude.value} - y: ${currentLongitude.value}');
|
||||
// zoomPanBehavior.focalLatLng =
|
||||
// MapLatLng(currentLatitude.value, currentLongitude.value);
|
||||
mapTileLayerController.updateMarkers([0]);
|
||||
});
|
||||
}
|
||||
|
||||
Future<String> getJsonFromAssets() async {
|
||||
return await rootBundle.loadString('assets/Files/telkek_0510.geojson');
|
||||
}
|
||||
|
||||
Future<bool> loadMapData() async {
|
||||
final String jsonString = await getJsonFromAssets();
|
||||
final Map<String, dynamic> jsonResponse = jsonDecode(jsonString);
|
||||
List<dynamic> feature = jsonResponse['features'];
|
||||
for (int i = 0; i < feature.length; i++) {
|
||||
mapModel.add(
|
||||
MapModel.fromJson(feature[i]['properties'] as Map<String, dynamic>));
|
||||
}
|
||||
|
||||
// _shapeSource = MapShapeSource.asset('assets/usa.json',
|
||||
// shapeDataField: 'name',
|
||||
// dataCount: _mapData.length,
|
||||
// primaryValueMapper: (int index) => _mapData[index].name!,
|
||||
// dataLabelMapper: (int index) => _mapData[index].name!,
|
||||
// shapeColorValueMapper: (int index) => _mapData[index].color);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class MapModel {
|
||||
// Data type
|
||||
Color? color;
|
||||
String? hrsz;
|
||||
String? telepules;
|
||||
String? id;
|
||||
|
||||
//constructor
|
||||
MapModel({this.id, this.telepules, this.hrsz, this.color});
|
||||
|
||||
// Method that assigns values to respective datatype variables
|
||||
factory MapModel.fromJson(Map<String, dynamic> json) {
|
||||
Color modelColor = Colors.amber;
|
||||
double opacity = 0.5;
|
||||
|
||||
/// While fetching the color codes as String from JSON. Use these codes to convert it as Color.
|
||||
//String hexColor = json['COLOR'] as String;
|
||||
// Color(int.parse(hexColor.substring(1, 7), radix: 16) + 0xFF000000);
|
||||
|
||||
// log("${json['id1']} - ${json['Telepules']} - ${json['Hrsz']}");
|
||||
|
||||
String telepules = json['Telepules'];
|
||||
if (telepules == 'Jágónak') {
|
||||
modelColor = Color.fromRGBO(55, 88, 187, opacity);
|
||||
} else if (telepules == 'Baranyajenő') {
|
||||
modelColor = Color.fromRGBO(159, 65, 214, opacity);
|
||||
} else if (telepules == 'Kercseliget') {
|
||||
modelColor = Color.fromRGBO(235, 209, 63, opacity);
|
||||
} else if (telepules == 'Dombóvár') {
|
||||
modelColor = Color.fromRGBO(99, 219, 169, opacity);
|
||||
} else if (telepules == 'Kaposszekcső') {
|
||||
modelColor = Color.fromRGBO(202, 122, 86, opacity);
|
||||
} else if (telepules == 'Csikóstőttős') {
|
||||
modelColor = Color.fromRGBO(145, 43, 43, opacity);
|
||||
} else if (telepules == 'Baranyajenő') {
|
||||
modelColor = Color.fromRGBO(159, 65, 214, opacity);
|
||||
} else if (telepules == 'Vásárosdombó') {
|
||||
modelColor = Color.fromRGBO(51, 238, 60, opacity);
|
||||
} else if (telepules == 'Meződ') {
|
||||
modelColor = Color.fromRGBO(99, 212, 216, opacity);
|
||||
} else if (telepules == 'Tarrós') {
|
||||
modelColor = Color.fromRGBO(224, 203, 236, opacity);
|
||||
} else if (telepules == 'Vázsnok') {
|
||||
modelColor = Color.fromRGBO(74, 155, 8, opacity);
|
||||
} else if (telepules == 'Sásd') {
|
||||
modelColor = Color.fromRGBO(143, 91, 112, opacity);
|
||||
}
|
||||
|
||||
return MapModel(
|
||||
id: json['id1'] as String,
|
||||
telepules: json['Telepules'],
|
||||
hrsz: json['Hrsz'],
|
||||
color: modelColor);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:syncfusion_flutter_maps/maps.dart';
|
||||
import 'package:terepi_seged/pages/map_test/presentation/controllers/map_test_controller.dart';
|
||||
|
||||
class MapTestView extends GetView<MapTestController> {
|
||||
const MapTestView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
child: Obx(
|
||||
() => controller.isInitialized.value
|
||||
? SfMaps(
|
||||
layers: [
|
||||
MapTileLayer(
|
||||
urlTemplate:
|
||||
'http://mt1.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}',
|
||||
zoomPanBehavior: controller.zoomPanBehavior,
|
||||
controller: controller.mapTileLayerController,
|
||||
initialMarkersCount: 1,
|
||||
markerBuilder: (BuildContext context, int index) {
|
||||
return MapMarker(
|
||||
latitude: controller.currentLatitude.value,
|
||||
longitude: controller.currentLongitude.value,
|
||||
size: const Size(20, 20),
|
||||
child: const Icon(
|
||||
Icons.location_on,
|
||||
color: Colors.yellow,
|
||||
),
|
||||
);
|
||||
},
|
||||
sublayers: [
|
||||
// MapShapeSublayer(
|
||||
// source: controller.kozigSource,
|
||||
// showDataLabels: true,
|
||||
// dataLabelSettings: const MapDataLabelSettings(
|
||||
// textStyle: TextStyle(
|
||||
// color: Colors.red,
|
||||
// fontSize: 12,
|
||||
// fontWeight: FontWeight.normal,
|
||||
// fontFamily: 'Times')),
|
||||
// color: Colors.transparent,
|
||||
// strokeColor: Colors.red,
|
||||
// strokeWidth: 2,
|
||||
// ),
|
||||
MapShapeSublayer(
|
||||
source: controller.mapSource,
|
||||
showDataLabels: true,
|
||||
dataLabelSettings: const MapDataLabelSettings(
|
||||
textStyle: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Times')),
|
||||
// color: Colors.white38,
|
||||
strokeColor: Colors.black,
|
||||
strokeWidth: 2,
|
||||
),
|
||||
MapPolylineLayer(
|
||||
polylines: List<MapPolyline>.generate(
|
||||
controller.lines2.length, (index) {
|
||||
return MapPolyline(
|
||||
points: controller.lines2[index],
|
||||
color: Colors.purple,
|
||||
width: 3);
|
||||
}).toSet()),
|
||||
MapPolylineLayer(
|
||||
polylines: List<MapPolyline>.generate(
|
||||
controller.lines2.length, (index) {
|
||||
return MapPolyline(
|
||||
points: controller.lines3[index],
|
||||
color: Colors.yellow,
|
||||
width: 3);
|
||||
}).toSet()),
|
||||
MapPolylineLayer(
|
||||
polylines: List<MapPolyline>.generate(
|
||||
controller.lines1.length, (index) {
|
||||
return MapPolyline(
|
||||
points: controller.lines1[index],
|
||||
color: Colors.yellow,
|
||||
width: 3);
|
||||
}).toSet()),
|
||||
],
|
||||
),
|
||||
// MapShapeLayer(
|
||||
// source: controller.mapSource,
|
||||
// showDataLabels: true,
|
||||
// dataLabelSettings: const MapDataLabelSettings(
|
||||
// textStyle: TextStyle(
|
||||
// color: Colors.black,
|
||||
// fontSize: 10,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// fontFamily: 'Times')),
|
||||
// zoomPanBehavior: controller.zoomPanBehavior,
|
||||
// )
|
||||
],
|
||||
)
|
||||
: const Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/measured_data/presentation/controllers/measured_data_controller.dart';
|
||||
|
||||
class MeasuredDataBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => MeasuredDataController());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:firebase_storage/firebase_storage.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/models/seismic_records.dart';
|
||||
import 'package:terepi_seged/pages/measured_data/presentation/views/seismogram_viewer_dialog.dart';
|
||||
|
||||
class MeasuredDataController extends GetxController {
|
||||
final CollectionReference _seismicRecords =
|
||||
FirebaseFirestore.instance.collection('seismicRecords');
|
||||
|
||||
// late Query<Map<String, dynamic>> records = _seismicRecords.orderBy('field');
|
||||
late Stream<QuerySnapshot> seismicRecordSnapshot;
|
||||
|
||||
@override
|
||||
void onReady() async {
|
||||
super.onReady();
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
|
||||
seismicRecordSnapshot = _seismicRecords
|
||||
// .orderBy('sourcePoint', descending: true)
|
||||
.where('gpsDateTime', isGreaterThan: DateTime(2024, 2, 25, 0, 0, 0))
|
||||
.orderBy('gpsDateTime', descending: true)
|
||||
.snapshots();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() async {
|
||||
super.onClose();
|
||||
|
||||
// seismicRecordSnapshot.
|
||||
}
|
||||
|
||||
void showSeismicImage(int ffid) async {
|
||||
late Uint8List image;
|
||||
Reference reference =
|
||||
FirebaseStorage.instance.ref().child('bp-4/${ffid}.jpg');
|
||||
|
||||
await reference
|
||||
.getData()
|
||||
.then((value) => {image = value!})
|
||||
.catchError((error) => {});
|
||||
|
||||
Get.to(
|
||||
() => SeismogramViewerDialog(
|
||||
imageUrl: '',
|
||||
image: image,
|
||||
),
|
||||
transition: Transition.downToUp);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/src/widgets/framework.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/measured_data/presentation/controllers/measured_data_controller.dart';
|
||||
import 'package:terepi_seged/pages/measured_data/presentation/views/seismogram_viewer_dialog.dart';
|
||||
|
||||
class MeasuredDataView extends GetView<MeasuredDataController> {
|
||||
const MeasuredDataView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
extendBody: true,
|
||||
appBar: AppBar(
|
||||
title: const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Mérési adatok'),
|
||||
Text(
|
||||
"Budapest",
|
||||
style: TextStyle(fontSize: 12.0),
|
||||
)
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 20.0),
|
||||
child: GestureDetector(
|
||||
onTap: () => Get.to(() => {}, transition: Transition.downToUp),
|
||||
child: const Icon(
|
||||
Icons.more_vert,
|
||||
size: 26.0,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
body: Column(children: [
|
||||
Text("Mérési adatok"),
|
||||
StreamBuilder<QuerySnapshot>(
|
||||
stream: controller.seismicRecordSnapshot,
|
||||
builder:
|
||||
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
return const Text('Hiba ...');
|
||||
}
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Text('Adatbetöltés ...');
|
||||
}
|
||||
return Expanded(
|
||||
child: ListView(
|
||||
// shrinkWrap: true,
|
||||
children: snapshot.data!.docs
|
||||
.map((DocumentSnapshot document) {
|
||||
Map<String, dynamic> data =
|
||||
document.data()! as Map<String, dynamic>;
|
||||
return ListTile(
|
||||
title: Text(data['sourcePoint'].toString()),
|
||||
subtitle: Text(
|
||||
'${data['sourceLine'].toString()} - ${(data['gpsDateTime'] as Timestamp).toDate()}'),
|
||||
trailing: Wrap(spacing: -16, children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
controller.showSeismicImage(data['ffid']);
|
||||
},
|
||||
icon: const Icon(Icons.image_outlined)),
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon:
|
||||
const Icon(Icons.arrow_forward_ios_sharp))
|
||||
]));
|
||||
})
|
||||
.toList()
|
||||
.cast(),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
]));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:photo_view/photo_view.dart';
|
||||
import 'package:terepi_seged/pages/measured_data/presentation/controllers/measured_data_controller.dart';
|
||||
import 'package:widget_zoom/widget_zoom.dart';
|
||||
|
||||
class SeismogramViewerDialog extends StatelessWidget {
|
||||
final controller = Get.find<MeasuredDataController>();
|
||||
final String imageUrl;
|
||||
final Uint8List image;
|
||||
// final double sourcePoint;
|
||||
SeismogramViewerDialog(
|
||||
{required this.imageUrl, required this.image, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: ListView(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
icon: const Icon(Icons.close)),
|
||||
TextButton(
|
||||
style: ButtonStyle(
|
||||
overlayColor:
|
||||
MaterialStateProperty.all(Colors.transparent)),
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
child: const Text(
|
||||
'Bezár',
|
||||
style: TextStyle(color: Colors.blue, fontSize: 14.0),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 15.0),
|
||||
child: Text(
|
||||
'Felvétel megtekintése ()',
|
||||
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10.0),
|
||||
child: Center(
|
||||
child: WidgetZoom(
|
||||
zoomWidget: Image(image: MemoryImage(image)),
|
||||
heroAnimationTag: 'tag',
|
||||
maxScaleFullscreen: 8,
|
||||
maxScaleEmbeddedView: 8,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/navigation/presentation/controllers/navigation_controller.dart';
|
||||
|
||||
class NavigationViewBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => NavigationViewController());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,967 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:flutter_map_geojson/flutter_map_geojson.dart';
|
||||
import 'package:flutter_map_polywidget/flutter_map_polywidget.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/date_time_patterns.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:location/location.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:nmea/nmea.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:permission_handler/permission_handler.dart'
|
||||
as permission_handler;
|
||||
import 'package:terepi_seged/eov/convert_coordinate.dart';
|
||||
import 'package:terepi_seged/eov/eov.dart';
|
||||
import 'package:terepi_seged/gnss_sentences/gngga.dart';
|
||||
import 'package:terepi_seged/gnss_sentences/gngst.dart';
|
||||
import 'package:terepi_seged/gnss_sentences/gnrmc.dart';
|
||||
import 'package:terepi_seged/models/point_to_measure.dart';
|
||||
import 'package:terepi_seged/models/point_with_description_model.dart';
|
||||
import 'package:proj4dart/proj4dart.dart' as proj4;
|
||||
|
||||
class NavigationViewController extends GetxController {
|
||||
// String gpsAddress = "E8:31:CD:14:8B:B2";
|
||||
// String gpsAddress = "98:CD:AC:62:FF:4E";
|
||||
RxString gpsAddress = "98:CD:AC:62:FF:36".obs;
|
||||
String gpsName = "TiGNSS Rover-FF4E";
|
||||
// String gpsName = "TiGNSS Rover-8BB2";
|
||||
static const double maxZoomValue = 25.0;
|
||||
Rx<bool> gpsIsConnected = false.obs;
|
||||
RxBool ntripIsConnected = false.obs;
|
||||
RxInt ntripDataPacketNumbers = 0.obs;
|
||||
RxInt ggaSenDataPacketNumber = 0.obs;
|
||||
RxString ggaSendLastTimeStr = "".obs;
|
||||
String _messageBuffer = "";
|
||||
late BluetoothConnection connection;
|
||||
late Socket socket;
|
||||
late StreamSubscription socketStreamSubscription;
|
||||
RxInt gpsReceivedData = 0.obs;
|
||||
RxBool hasGpsValidData = false.obs;
|
||||
RxBool isMapMoveToCenter = true.obs;
|
||||
DateTime lastGpsRefreshTime = DateTime.now();
|
||||
String utcOfPositionFix = "";
|
||||
String utcDateOfPositionFix = "";
|
||||
RxInt ntripReceivedData = 0.obs;
|
||||
final NmeaDecoder nmeaDecoder = NmeaDecoder();
|
||||
String lastGgaMessage = '';
|
||||
DateTime lastSendTimeGgaMessage =
|
||||
DateTime.now().add(const Duration(seconds: -30));
|
||||
|
||||
NumberFormat formatEov = NumberFormat("##0,000.0", "hu-HU");
|
||||
NumberFormat formatEovForFile = NumberFormat("#####0.0", "hu-HU");
|
||||
NumberFormat formatWgs84Sec = NumberFormat('00.000', 'hu-HU');
|
||||
|
||||
RxDouble gpsLatitude = 0.0.obs;
|
||||
RxString gpsLatitudeDirection = "".obs;
|
||||
RxDouble gpsLongitude = 0.0.obs;
|
||||
RxString gpsLongitudeDirection = "".obs;
|
||||
RxDouble gpsAltitude = 0.0.obs;
|
||||
RxInt gpsQuality = 0.obs;
|
||||
RxDouble gpsLatitudeError = 0.0.obs;
|
||||
RxDouble gpsLongitudeError = 0.0.obs;
|
||||
RxDouble gpsAltitudeError = 0.0.obs;
|
||||
Rx<DateTime> gpsDateTime = DateTime(2000).obs;
|
||||
Rx<Eov> eov = Eov(0, 0).obs;
|
||||
RxInt latDegree = 0.obs;
|
||||
RxInt latMin = 0.obs;
|
||||
RxDouble latSec = 0.0.obs;
|
||||
RxInt longDegree = 0.obs;
|
||||
RxInt longMin = 0.obs;
|
||||
RxDouble longSec = 0.0.obs;
|
||||
|
||||
RxDouble currentLongitude = 0.0.obs;
|
||||
RxDouble currentLatitude = 0.0.obs;
|
||||
RxDouble currentZoom = 18.0.obs;
|
||||
late final MapController mapController;
|
||||
final currentLocationMarker = <Marker>[];
|
||||
final pointNotesMarker = <Marker>[];
|
||||
|
||||
List<PointToMeasure> pointsToMeasure = <PointToMeasure>[];
|
||||
final pointsToMeasureMarker = <Marker>[];
|
||||
final pointsToMeasureLabel = <PolyWidget>[];
|
||||
final pointsToMeasureDropDownMenuItem = <DropdownMenuItem<int>>[];
|
||||
RxInt pointsToMeasureSelectedValue = (-1).obs;
|
||||
RxDouble distance = 0.0.obs;
|
||||
|
||||
TextEditingController pointIdController = TextEditingController();
|
||||
TextEditingController pointDescriptionController = TextEditingController();
|
||||
TextEditingController gpsHeightController = TextEditingController();
|
||||
TextEditingController ntripUsernameController = TextEditingController();
|
||||
TextEditingController ntripPasswordController = TextEditingController();
|
||||
TextEditingController vehicleNumberController = TextEditingController();
|
||||
|
||||
int pointId = 1;
|
||||
Rx<bool> pointMeasuringDirectionForward = true.obs;
|
||||
|
||||
List<PointWithDescription> pointWithDescriptionList = [];
|
||||
late Directory? directory;
|
||||
late File dataFile;
|
||||
late File gpsFile;
|
||||
late File internalGpsFile;
|
||||
late Timer internalGpsLogTimer;
|
||||
|
||||
late proj4.Projection eovProj, wgsProj;
|
||||
RxBool mapIsInitialized = false.obs;
|
||||
|
||||
GeoJsonParser parser = GeoJsonParser(defaultMarkerColor: Colors.yellow);
|
||||
|
||||
final CollectionReference _vibratorTracker =
|
||||
FirebaseFirestore.instance.collection('vibratorTracker');
|
||||
DateTime lastGpsDataSaveTime = DateTime(2000, 1, 1, 0, 0, 0);
|
||||
int vehicleNumber = 2;
|
||||
late Location internalGpsLogger;
|
||||
Location internalGpsLocation = Location();
|
||||
late StreamSubscription<LocationData> internalGpsLocationSubscription;
|
||||
|
||||
// late SMIBool gpsTrigger;
|
||||
// late StateMachineController riveGpsIconController;
|
||||
|
||||
@override
|
||||
void onInit() async {
|
||||
super.onInit();
|
||||
final bytes = (await rootBundle.load('assets/Grids/etrs2eov_notowgs.gsb'))
|
||||
.buffer
|
||||
.asUint8List();
|
||||
proj4.Projection.nadgrid('Etrs2Eov', bytes);
|
||||
var def =
|
||||
'+proj=somerc +lat_0=47.14439372222222 +lon_0=19.04857177777778 +k_0=0.99993 +x_0=650000 +y_0=200000 +ellps=GRS67 +towgs84=52.17,-71.82,-14.9,0,0,0,0 +units=m +nadgrids=@ignorable,Etrs2Eov,null +no_defs';
|
||||
|
||||
// Named Projection signature, later find it from anywhere via Projection.get('EPSG:23700')
|
||||
eovProj = proj4.Projection.add('EPSG:23700', def);
|
||||
wgsProj = proj4.Projection.WGS84;
|
||||
//Loading, Success, Error handle with 1 line of code
|
||||
nmeaDecoder
|
||||
..registerTalkerSentence("GGA", (line) => Gngga(raw: line))
|
||||
..registerTalkerSentence("RMC", (line) => Gnrmc(raw: line))
|
||||
..registerTalkerSentence("GST", (line) => Gngst(raw: line));
|
||||
|
||||
mapController = MapController();
|
||||
|
||||
// riveGpsIconController = RiveUtils.getRiveController(Artboard(),
|
||||
// stateMachineName: "gps_Interactivity");
|
||||
// gpsTrigger = riveGpsIconController.findSMI("active");
|
||||
|
||||
mapIsInitialized.value = true;
|
||||
vehicleNumberController.text = vehicleNumber.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
super.onClose();
|
||||
FlutterBluetoothSerial.instance.setPairingRequestHandler(null);
|
||||
if (gpsIsConnected.value) {
|
||||
connection.close();
|
||||
// connection = null;
|
||||
print("BluetoothTestController dispose ....");
|
||||
}
|
||||
pointDescriptionController.dispose();
|
||||
pointIdController.dispose();
|
||||
gpsHeightController.dispose();
|
||||
ntripUsernameController.dispose();
|
||||
ntripPasswordController.dispose();
|
||||
vehicleNumberController.dispose();
|
||||
|
||||
// if (internalGpsLogTimer.isActive) {
|
||||
// internalGpsLogTimer.cancel();
|
||||
// }
|
||||
|
||||
internalGpsLocationSubscription.cancel();
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() async {
|
||||
super.onReady();
|
||||
|
||||
_getInitialLocation();
|
||||
|
||||
String data = await rootBundle.loadString('assets/Files/kozmuvek.geojson');
|
||||
parser.parseGeoJsonAsString(data);
|
||||
|
||||
if (await permission_handler.Permission.storage.isGranted) {
|
||||
print("Storage permission is ok ...");
|
||||
} else {
|
||||
var result = await permission_handler.Permission.storage.request();
|
||||
if (result == permission_handler.PermissionStatus.granted) {
|
||||
print("Storage permission request is ok ....");
|
||||
} else {
|
||||
print("No storage permission");
|
||||
}
|
||||
}
|
||||
if (await permission_handler.Permission.manageExternalStorage.isGranted) {
|
||||
print("External storage permission is ok ...");
|
||||
} else {
|
||||
var result =
|
||||
await permission_handler.Permission.manageExternalStorage.request();
|
||||
if (result == permission_handler.PermissionStatus.granted) {
|
||||
print("External storage permission request is ok ....");
|
||||
} else {
|
||||
print("No external storage permission");
|
||||
}
|
||||
}
|
||||
|
||||
directory = await getExternalStorageDirectory();
|
||||
print(directory!.path);
|
||||
// String newPath = '';
|
||||
// List<String> folders = directory!.path.split("/");
|
||||
// for (int i = 1; i < folders.length; i++) {
|
||||
// String folder = folders[i];
|
||||
// if (folder != "Android") {
|
||||
// newPath += "/" + folder;
|
||||
// } else {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// newPath = newPath + "/TerepisSegedApp";
|
||||
// directory = Directory(newPath);
|
||||
if (!await directory!.exists()) {
|
||||
await directory!.create(recursive: true);
|
||||
}
|
||||
dataFile = File("${directory!.path}/data.txt");
|
||||
gpsFile = File("${directory!.path}/GpsData.txt");
|
||||
internalGpsFile = File("${directory!.path}/internalGpsData.txt");
|
||||
|
||||
if (await directory!.exists()) {
|
||||
if (!await dataFile.exists()) {
|
||||
dataFile.writeAsString(
|
||||
"Id;DateTime;Description;EovX;EovY;Latitude;Longitude;Altitude;Hor.Err;Vert.Err\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (await directory!.exists()) {
|
||||
if (!await internalGpsFile.exists()) {
|
||||
internalGpsFile.writeAsString(
|
||||
"Vehicle;DateTime;Latitude;Longitude;Altitude;Accuracy\r\n");
|
||||
}
|
||||
}
|
||||
if (await directory!.exists()) {
|
||||
if (!await gpsFile.exists()) {
|
||||
gpsFile.writeAsString(
|
||||
"Vehicle;DateTime;Latitude;Longitude;Altitude;Accuracy\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
gpsHeightController.text = '1.7';
|
||||
|
||||
internalGpsLogger = Location();
|
||||
await internalGpsLocation.changeSettings(interval: 10000);
|
||||
|
||||
internalGpsLocationSubscription =
|
||||
internalGpsLogger.onLocationChanged.listen((LocationData value) {
|
||||
double? longitude;
|
||||
double? latitude;
|
||||
double? accuracy;
|
||||
double? altitude;
|
||||
DateTime time;
|
||||
double? speed;
|
||||
latitude = value.latitude ?? 0.0;
|
||||
longitude = value.longitude ?? 0.0;
|
||||
accuracy = value.accuracy ?? 0.0;
|
||||
altitude = value.altitude ?? 0.0;
|
||||
double? timestamp = value.time ?? 0.0;
|
||||
time = DateTime.fromMillisecondsSinceEpoch(timestamp.toInt());
|
||||
speed = value.speed ?? 0.0;
|
||||
|
||||
print("internalGpsLogTimer -> getLocation $time");
|
||||
|
||||
internalGpsFile.writeAsString(
|
||||
"$vehicleNumber;$time;$latitude;$longitude;$altitude;$accuracy\r\n");
|
||||
|
||||
_vibratorTracker.add({
|
||||
"gpsType": 0,
|
||||
"vibratorNumber": vehicleNumber,
|
||||
"gpsDateTime": time,
|
||||
"latitude": latitude,
|
||||
"longitude": longitude,
|
||||
"altitude": altitude,
|
||||
"horizontalError": accuracy,
|
||||
"speed": speed,
|
||||
"createdAt": DateTime.timestamp()
|
||||
});
|
||||
});
|
||||
|
||||
// internalGpsLogTimer =
|
||||
// Timer.periodic(const Duration(seconds: 10), (timer) async {
|
||||
// double? longitude;
|
||||
// double? latitude;
|
||||
// double? accuracy;
|
||||
// double? altitude;
|
||||
// DateTime time;
|
||||
// double? speed;
|
||||
|
||||
// print("internalGpsLogTimer -> out");
|
||||
|
||||
// LocationData value = await internalGpsLocation.getLocation();
|
||||
// latitude = value.latitude ?? 0.0;
|
||||
// longitude = value.longitude ?? 0.0;
|
||||
// accuracy = value.accuracy ?? 0.0;
|
||||
// altitude = value.altitude ?? 0.0;
|
||||
// double? timestamp = value.time ?? 0.0;
|
||||
// time = DateTime.fromMillisecondsSinceEpoch(timestamp.toInt());
|
||||
// speed = value.speed ?? 0.0;
|
||||
|
||||
// print("internalGpsLogTimer -> getLocation $time");
|
||||
|
||||
// internalGpsFile.writeAsString(
|
||||
// "$vehicleNumber;$time;$latitude;$longitude;$altitude;$accuracy\r\n");
|
||||
|
||||
// _vibratorTracker.add({
|
||||
// "gpsType": 0,
|
||||
// "vibratorNumber": vehicleNumber,
|
||||
// "gpsDateTime": time,
|
||||
// "latitude": latitude,
|
||||
// "longitude": longitude,
|
||||
// "altitude": altitude,
|
||||
// "horizontalError": accuracy,
|
||||
// "speed": speed,
|
||||
// "createdAt": DateTime.timestamp()
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
||||
void _getInitialLocation() async {
|
||||
bool servicedEnabled;
|
||||
PermissionStatus permissionGranted;
|
||||
LocationData locationData;
|
||||
Location location = Location();
|
||||
|
||||
servicedEnabled = await location.serviceEnabled();
|
||||
if (!servicedEnabled) {
|
||||
servicedEnabled = await location.requestService();
|
||||
if (!servicedEnabled) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
permissionGranted = await location.hasPermission();
|
||||
if (permissionGranted == PermissionStatus.denied) {
|
||||
permissionGranted = await location.requestPermission();
|
||||
if (permissionGranted != PermissionStatus.granted) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
locationData = await location.getLocation();
|
||||
currentLatitude.value = locationData.latitude ?? 0.0;
|
||||
currentLongitude.value = locationData.longitude ?? 0.0;
|
||||
|
||||
print("Current location initialized -> $currentLatitude $currentLongitude");
|
||||
mapController.move(LatLng(currentLatitude.value, currentLongitude.value),
|
||||
currentZoom.value);
|
||||
_updateCurrentLocationMarker();
|
||||
}
|
||||
|
||||
void connectToGps() {
|
||||
if (gpsIsConnected.value == false) {
|
||||
BluetoothConnection.toAddress(gpsAddress.value).then((value) {
|
||||
connection = value;
|
||||
gpsIsConnected.value = true;
|
||||
print("GPS is connected ...");
|
||||
|
||||
connection.input!.listen(_onDataReceived);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void disconnectFromGps() {
|
||||
if (gpsIsConnected.value) {
|
||||
connection.close();
|
||||
gpsIsConnected.value = false;
|
||||
print("GPS is disconnected ....");
|
||||
}
|
||||
if (ntripIsConnected.value) {
|
||||
disconnectFromNtripServer();
|
||||
}
|
||||
}
|
||||
|
||||
void connectToNtripServer() async {
|
||||
// socket = await Socket.connect(InternetAddress('3.23.52.207'), 2101,
|
||||
// timeout: const Duration(seconds: 5));
|
||||
socket = await Socket.connect(InternetAddress('84.206.45.44'), 2101,
|
||||
timeout: const Duration(seconds: 5));
|
||||
socket.asBroadcastStream;
|
||||
ntripIsConnected.value = true;
|
||||
|
||||
socket.encoding = ascii;
|
||||
print("Connected to ntrip server ....");
|
||||
|
||||
// String header = "GET /KOVARIK HTTP/1.1\r\n";
|
||||
String header = "GET /SGO_RTK3.2 HTTP/1.1\r\n";
|
||||
|
||||
header += "User-Agent: SharpGps iter.dk\r\n";
|
||||
header += "Accept: */*\r\nConnection: close\r\n";
|
||||
// header += "Authorization: Basic ${_toBase64("info@mail.app-dev.hu:")}\r\n";
|
||||
header += "Authorization: Basic ${_toBase64("elgi08:Laszl0stef1")}\r\n";
|
||||
// header += "Host:rtk2go.com:2101\r\n";
|
||||
header += "Host:gnssnet.hu:2101\r\n";
|
||||
header += "Ntrip-Vesrsion:Ntrip/2.0\r\n";
|
||||
header += "\r\n";
|
||||
|
||||
// listen for responses from the server
|
||||
socketStreamSubscription = socket.listen(
|
||||
// handle data from the server
|
||||
(Uint8List data) {
|
||||
// "ICY 200 OK" - first response
|
||||
final serverResponse = String.fromCharCodes(data);
|
||||
ntripReceivedData.value = data.length;
|
||||
ntripDataPacketNumbers.value++;
|
||||
if (gpsIsConnected.value) {
|
||||
if (data.length > 14) {
|
||||
connection.output.add(data);
|
||||
}
|
||||
}
|
||||
print('Server: $ntripReceivedData');
|
||||
},
|
||||
|
||||
// handle errors
|
||||
onError: (error) {
|
||||
print(error);
|
||||
socket.destroy();
|
||||
},
|
||||
|
||||
// handle server ending connection
|
||||
onDone: () async {
|
||||
print('Server left.');
|
||||
socketStreamSubscription.cancel();
|
||||
await socket.flush();
|
||||
ntripIsConnected.value = false;
|
||||
ntripReceivedData.value = 0;
|
||||
socket.destroy();
|
||||
},
|
||||
);
|
||||
|
||||
socket.add(_convertStringToUint8List(header));
|
||||
|
||||
// sendGgaMessage(lastGgaMessage);
|
||||
}
|
||||
|
||||
void disconnectFromNtripServer() async {
|
||||
socketStreamSubscription.cancel();
|
||||
await socket.flush();
|
||||
socket.close();
|
||||
socket.destroy();
|
||||
ntripReceivedData.value = 0;
|
||||
ntripIsConnected.value = false;
|
||||
print("Disconnect from ntrip server....");
|
||||
}
|
||||
|
||||
void _onDataReceived(Uint8List data) {
|
||||
String sentence = "";
|
||||
|
||||
print("Bluetooth received -> ${data.length} byte(s)");
|
||||
String dataString = String.fromCharCodes(data);
|
||||
int index = data.indexOf(13);
|
||||
|
||||
if (~index != 0) {
|
||||
sentence = _messageBuffer + dataString.substring(0, index);
|
||||
_messageBuffer = dataString.substring(index);
|
||||
} else {
|
||||
_messageBuffer = _messageBuffer + dataString;
|
||||
}
|
||||
|
||||
// print("Message ($count): $sentence");
|
||||
_processGnssMessage(sentence);
|
||||
}
|
||||
|
||||
String _toBase64(String str) {
|
||||
final bytes = ascii.encode(str);
|
||||
final base64Str = base64.encode(bytes);
|
||||
|
||||
return base64Str;
|
||||
}
|
||||
|
||||
Uint8List _convertStringToUint8List(String str) {
|
||||
final List<int> codeUnits = str.codeUnits;
|
||||
final Uint8List unit8List = Uint8List.fromList(codeUnits);
|
||||
return unit8List;
|
||||
}
|
||||
|
||||
void _processGnssMessage(String message) {
|
||||
LineSplitter lineSplitter = const LineSplitter();
|
||||
List<String> lines = lineSplitter.convert(message);
|
||||
|
||||
if (lines.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String line in lines) {
|
||||
if (line.trim().isEmpty) {
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("\$GNGGA")) {
|
||||
final sentence = nmeaDecoder.decode(line);
|
||||
if (sentence!.valid && sentence is Gngga) {
|
||||
hasGpsValidData.value = sentence.gpsQualityIndicator > 0;
|
||||
if (hasGpsValidData.value) {
|
||||
if (DateTime.now().difference(lastGpsRefreshTime).inSeconds >= 0) {
|
||||
lastGpsRefreshTime = DateTime.now();
|
||||
utcOfPositionFix = sentence.utcOfPositionFix;
|
||||
gpsLatitude.value = sentence.latitude;
|
||||
gpsLatitudeDirection.value = sentence.latitudeDirection;
|
||||
gpsLongitude.value = sentence.longitude;
|
||||
gpsLongitudeDirection.value = sentence.longitudeDirection;
|
||||
gpsAltitude.value = sentence.altitudeAboveMeanSeaLevel;
|
||||
gpsQuality.value = sentence.gpsQualityIndicator;
|
||||
eov.value = ConvertCoordinate.ConvertWgsToEov(
|
||||
gpsLatitude.value, gpsLongitude.value);
|
||||
|
||||
if (pointsToMeasureSelectedValue.value >= 0) {
|
||||
double coordX =
|
||||
pointsToMeasure[pointsToMeasureSelectedValue.value].coordX;
|
||||
double coordY =
|
||||
pointsToMeasure[pointsToMeasureSelectedValue.value].coordY;
|
||||
var eovCoord = proj4.Point(x: coordX, y: coordY);
|
||||
var wgsCoord = eovProj.transform(wgsProj, eovCoord);
|
||||
distance.value = calculateDistance(
|
||||
LatLng(gpsLatitude.value, gpsLongitude.value),
|
||||
LatLng(wgsCoord.y, wgsCoord.x));
|
||||
}
|
||||
latDegree.value = ConvertCoordinate.toDegree(gpsLatitude.value);
|
||||
latMin.value = ConvertCoordinate.toMinute(gpsLatitude.value);
|
||||
latSec.value = ConvertCoordinate.toSecond(gpsLatitude.value);
|
||||
longDegree.value = ConvertCoordinate.toDegree(gpsLongitude.value);
|
||||
longMin.value = ConvertCoordinate.toMinute(gpsLongitude.value);
|
||||
longSec.value = ConvertCoordinate.toSecond(gpsLongitude.value);
|
||||
currentLatitude.value = gpsLatitude.value;
|
||||
currentLongitude.value = gpsLongitude.value;
|
||||
_updateCurrentLocationMarker();
|
||||
lastGgaMessage = line;
|
||||
if (ntripIsConnected.value &&
|
||||
(DateTime.now()
|
||||
.difference(lastSendTimeGgaMessage)
|
||||
.inSeconds >=
|
||||
30)) {
|
||||
sendGgaMessage(lastGgaMessage);
|
||||
print("Send GGA message: $lastGgaMessage");
|
||||
ggaSenDataPacketNumber.value++;
|
||||
ggaSendLastTimeStr.value = utcOfPositionFix;
|
||||
lastSendTimeGgaMessage = DateTime.now();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (line.startsWith("\$GNGST") && hasGpsValidData.value) {
|
||||
final sentence = nmeaDecoder.decode(line);
|
||||
if (sentence!.valid && sentence is Gngst) {
|
||||
gpsLatitudeError.value = sentence.latitudeError;
|
||||
gpsLongitudeError.value = sentence.longitudeError;
|
||||
gpsAltitudeError.value = sentence.heightError;
|
||||
}
|
||||
}
|
||||
if (line.startsWith("\$GNRMC") && hasGpsValidData.value) {
|
||||
final sentence = nmeaDecoder.decode(line);
|
||||
if (sentence!.valid && sentence is Gnrmc) {
|
||||
utcDateOfPositionFix = sentence.date;
|
||||
if (utcDateOfPositionFix.isNotEmpty && utcOfPositionFix.isNotEmpty) {
|
||||
gpsDateTime.value = DateTime(
|
||||
2000 +
|
||||
int.parse(
|
||||
"${utcDateOfPositionFix[4]}${utcDateOfPositionFix[5]}"),
|
||||
int.parse(
|
||||
"${utcDateOfPositionFix[2]}${utcDateOfPositionFix[3]}"),
|
||||
int.parse(
|
||||
"${utcDateOfPositionFix[0]}${utcDateOfPositionFix[1]}"),
|
||||
int.parse("${utcOfPositionFix[0]}${utcOfPositionFix[1]}"),
|
||||
int.parse("${utcOfPositionFix[2]}${utcOfPositionFix[3]}"),
|
||||
int.parse("${utcOfPositionFix[4]}${utcOfPositionFix[5]}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DateTime.now().difference(lastGpsDataSaveTime).inSeconds >= 10 &&
|
||||
gpsQuality.value > 0) {
|
||||
_savePositionToDatabase();
|
||||
}
|
||||
}
|
||||
|
||||
void _savePositionToDatabase() {
|
||||
_vibratorTracker.add({
|
||||
"gpsType": 1,
|
||||
"vibratorNumber": vehicleNumber,
|
||||
"gpsQuality": gpsQuality.value,
|
||||
"gpsDateTime": gpsDateTime.value,
|
||||
"latitude": gpsLatitude.value,
|
||||
"longitude": gpsLongitude.value,
|
||||
"altitude": gpsAltitude.value,
|
||||
"eovY": eov.value.Y,
|
||||
"eovX": eov.value.X,
|
||||
"horizontalError": max(gpsLatitudeError.value, gpsLongitudeError.value),
|
||||
"verticalError": gpsAltitudeError.value,
|
||||
"antennaHeight": double.parse(gpsHeightController.text),
|
||||
"createdAt": DateTime.timestamp()
|
||||
});
|
||||
lastGpsDataSaveTime = DateTime.now();
|
||||
}
|
||||
|
||||
String getGpsQualityIndicator({required int quality}) {
|
||||
String qualityStr = "Invalid";
|
||||
switch (quality) {
|
||||
case 0:
|
||||
{
|
||||
qualityStr = "Invalid";
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
qualityStr = "Standard GPS (2D/3D)";
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
qualityStr = "Differential GPS";
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
qualityStr = "RTK Fix";
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
qualityStr = "RTK Float";
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
qualityStr = "Estimated (DR) Fix";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
qualityStr = "Invalid (-1)";
|
||||
}
|
||||
}
|
||||
return qualityStr;
|
||||
}
|
||||
|
||||
void mapZoomOut() {
|
||||
double cLat, cLong;
|
||||
if (currentZoom.value > 0) {
|
||||
currentZoom.value = currentZoom.value - 1;
|
||||
cLat = isMapMoveToCenter.value
|
||||
? currentLatitude.value
|
||||
: mapController.camera.center.latitude;
|
||||
cLong = isMapMoveToCenter.value
|
||||
? currentLongitude.value
|
||||
: mapController.camera.center.longitude;
|
||||
mapController.move(LatLng(cLat, cLong), currentZoom.value);
|
||||
}
|
||||
}
|
||||
|
||||
void mapZoomIn() {
|
||||
double cLat, cLong;
|
||||
if (currentZoom.value < maxZoomValue) {
|
||||
currentZoom.value++;
|
||||
cLat = isMapMoveToCenter.value
|
||||
? currentLatitude.value
|
||||
: mapController.camera.center.latitude;
|
||||
cLong = isMapMoveToCenter.value
|
||||
? currentLongitude.value
|
||||
: mapController.camera.center.longitude;
|
||||
mapController.move(LatLng(cLat, cLong), currentZoom.value);
|
||||
}
|
||||
}
|
||||
|
||||
void _updateCurrentLocationMarker() {
|
||||
currentLocationMarker.clear();
|
||||
currentLocationMarker.add(Marker(
|
||||
point: LatLng(currentLatitude.value, currentLongitude.value),
|
||||
width: 15.0,
|
||||
height: 15.0,
|
||||
child: Container(
|
||||
width: 15.0,
|
||||
height: 15.0,
|
||||
decoration: BoxDecoration(
|
||||
color: getCurrentLocationMarkerColor(quality: gpsQuality.value),
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(width: 1.5, color: Colors.white)),
|
||||
)));
|
||||
if (isMapMoveToCenter.value) {
|
||||
mapController.move(LatLng(currentLatitude.value, currentLongitude.value),
|
||||
currentZoom.value);
|
||||
}
|
||||
}
|
||||
|
||||
Color getCurrentLocationMarkerColor({required int quality}) {
|
||||
Color qualityStr = Colors.black;
|
||||
switch (quality) {
|
||||
case 0:
|
||||
{
|
||||
qualityStr = Colors.black;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
qualityStr = Colors.red;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
qualityStr = Colors.blue;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
qualityStr = Colors.green;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
qualityStr = Colors.orange;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
qualityStr = Colors.yellow;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
qualityStr = Colors.white;
|
||||
}
|
||||
}
|
||||
return qualityStr;
|
||||
}
|
||||
|
||||
void onBottomNavigationBarTap(int index) async {
|
||||
print("OnBottomNavTap -> $index");
|
||||
if (index == 0) {
|
||||
pointIdController.text =
|
||||
'${pointsToMeasure[pointsToMeasureSelectedValue.value].id}';
|
||||
pointIdController.text = pointId.toString();
|
||||
pointDescriptionController.text = "";
|
||||
Get.dialog(
|
||||
AlertDialog(
|
||||
title: const Text("Pont rögzítése"),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextField(
|
||||
controller: pointIdController,
|
||||
autofocus: true,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(), labelText: 'Azonosító'),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20.0,
|
||||
),
|
||||
TextField(
|
||||
controller: pointDescriptionController,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(), labelText: 'Leírás'),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
TextField(
|
||||
controller: gpsHeightController,
|
||||
autofocus: true,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(), labelText: 'GPS magasság'),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
OutlinedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
minimumSize: const Size(120.0, 40.0)),
|
||||
child: const Text(
|
||||
"Mégsem",
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
),
|
||||
OutlinedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
minimumSize: const Size(120.0, 40.0)),
|
||||
child: const Text(
|
||||
"Ment",
|
||||
style: TextStyle(
|
||||
color: Colors.green, fontWeight: FontWeight.bold),
|
||||
),
|
||||
onPressed: () async {
|
||||
pointId = int.parse(pointIdController.text);
|
||||
pointWithDescriptionList.add(PointWithDescription(
|
||||
pointId,
|
||||
gpsDateTime.value,
|
||||
pointDescriptionController.text,
|
||||
eov.value.Y,
|
||||
eov.value.X,
|
||||
gpsLatitude.value,
|
||||
gpsLongitude.value,
|
||||
max(gpsLatitudeError.value, gpsLongitudeError.value),
|
||||
gpsAltitudeError.value));
|
||||
print(
|
||||
"pointWithDescriptionList -> ${pointWithDescriptionList.length}");
|
||||
|
||||
pointNotesMarker.add(Marker(
|
||||
point: LatLng(gpsLatitude.value, gpsLongitude.value),
|
||||
width: 15.0,
|
||||
height: 15.0,
|
||||
child: Container(
|
||||
width: 15.0,
|
||||
height: 15.0,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.purple,
|
||||
shape: BoxShape.circle,
|
||||
border:
|
||||
Border.all(width: 1.0, color: Colors.black)),
|
||||
)));
|
||||
await dataFile.writeAsString(
|
||||
"$pointId;$gpsDateTime;${pointDescriptionController.text};${formatEovForFile.format(eov.value.Y)};${formatEovForFile.format(eov.value.X)};$gpsLatitude;$gpsLongitude;$gpsAltitude;${max(gpsLatitudeError.value, gpsLongitudeError.value)};$gpsAltitudeError;${gpsHeightController.text}\r\n",
|
||||
mode: FileMode.append);
|
||||
|
||||
pointId--;
|
||||
pointsToMeasureSelectedValue.value -= 1;
|
||||
|
||||
Get.back();
|
||||
},
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
barrierDismissible: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void sendGgaMessage(String ggaMessage) {
|
||||
if (ntripIsConnected.value && ggaMessage.isNotEmpty) {
|
||||
socket.add(_convertStringToUint8List("$ggaMessage\r\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void setIsMapMoveToCenter() {
|
||||
// isMapMoveToCenter.value = !isMapMoveToCenter.value;
|
||||
isMapMoveToCenter.value = !isMapMoveToCenter.value;
|
||||
}
|
||||
|
||||
void ReadPointsFromFile() async {
|
||||
File? file;
|
||||
FilePickerResult? result = await FilePicker.platform.pickFiles();
|
||||
|
||||
if (result != null) {
|
||||
file = File(result.files.single.path!);
|
||||
} else {
|
||||
print("No file selected");
|
||||
}
|
||||
if (await file!.exists()) {
|
||||
pointsToMeasure.clear();
|
||||
final content = await file.readAsLines();
|
||||
print('Length: -> ${content.length}');
|
||||
|
||||
for (final (index, item) in content.indexed) {
|
||||
if (index == 0) {
|
||||
continue;
|
||||
}
|
||||
var items = item.split(";");
|
||||
if (items.length >= 3) {
|
||||
var id = int.tryParse(items[0]);
|
||||
var coordX = double.tryParse(items[1].replaceAll(',', '.'));
|
||||
var coordY = double.tryParse(items[2].replaceAll(',', '.'));
|
||||
|
||||
if (id != null && coordX != null && coordY != null) {
|
||||
pointsToMeasure
|
||||
.add(PointToMeasure(id: id, coordX: coordX, coordY: coordY));
|
||||
|
||||
var eovCoord = proj4.Point(x: coordX, y: coordY);
|
||||
var wgsCoord = eovProj.transform(wgsProj, eovCoord);
|
||||
|
||||
print("Lat -> ${wgsCoord.x}, Long -> ${wgsCoord.y}");
|
||||
|
||||
pointsToMeasureMarker.add(Marker(
|
||||
point: LatLng(wgsCoord.y, wgsCoord.x),
|
||||
width: 15.0,
|
||||
height: 15.0,
|
||||
child: Container(
|
||||
width: 15.0,
|
||||
height: 15.0,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.purple,
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(width: 1.0, color: Colors.black)),
|
||||
)));
|
||||
|
||||
pointsToMeasureLabel.add(PolyWidget(
|
||||
center: LatLng(wgsCoord.y + 0.0000075, wgsCoord.x + 0.0000075),
|
||||
widthInMeters: 3,
|
||||
heightInMeters: 3,
|
||||
// constraints: const BoxConstraints(
|
||||
// minWidth: 250,
|
||||
// maxWidth: 350,
|
||||
// ),
|
||||
child: FittedBox(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Text(
|
||||
' $id ',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.yellow,
|
||||
fontSize: 12.0),
|
||||
),
|
||||
),
|
||||
)));
|
||||
|
||||
pointsToMeasureDropDownMenuItem.add(DropdownMenuItem<int>(
|
||||
value: index - 1,
|
||||
child: Text('$id'),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
pointsToMeasureSelectedValue.value = 0;
|
||||
print('Converted points number -> ${pointsToMeasure.length}');
|
||||
}
|
||||
}
|
||||
|
||||
void pointsToMeasureSelectedValueChanged(int value) {
|
||||
pointsToMeasureSelectedValue.value = value;
|
||||
print('Selected point -> ${pointsToMeasureSelectedValue.value}');
|
||||
}
|
||||
|
||||
double calculateDistance(LatLng start, LatLng end) {
|
||||
const double earthRadius = 6371.0; // Radius of the Earth in kilometers
|
||||
|
||||
// Convert coordinates to radians
|
||||
final double lat1 = start.latitude * (pi / 180.0);
|
||||
final double lon1 = start.longitude * (pi / 180.0);
|
||||
final double lat2 = end.latitude * (pi / 180.0);
|
||||
final double lon2 = end.longitude * (pi / 180.0);
|
||||
|
||||
// Calculate the differences between the coordinates
|
||||
final double dLat = lat2 - lat1;
|
||||
final double dLon = lon2 - lon1;
|
||||
|
||||
// Apply the Haversine formula
|
||||
final double a = sin(dLat / 2) * sin(dLat / 2) +
|
||||
cos(lat1) * cos(lat2) * sin(dLon / 2) * sin(dLon / 2);
|
||||
final double c = 2 * atan2(sqrt(a), sqrt(1 - a));
|
||||
final double distance = earthRadius * c;
|
||||
|
||||
return distance; // Distance in kilometers, add "*1000" to get meters
|
||||
}
|
||||
|
||||
void addMeasuredPoint() {
|
||||
// _measuredPoints.add({"id": 4001, "latitude": 46.3455, "longitude": 19.652});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,427 @@
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map_polywidget/flutter_map_polywidget.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
import 'package:rive/rive.dart';
|
||||
import 'package:terepi_seged/pages/navigation/presentation/controllers/navigation_controller.dart';
|
||||
import 'package:terepi_seged/pages/navigation/presentation/views/settings_dialog.dart';
|
||||
import 'package:terepi_seged/utils/rive_utils.dart';
|
||||
|
||||
class NavigationView extends GetView<NavigationViewController> {
|
||||
const NavigationView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
late SMIBool gpsTrigger;
|
||||
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
extendBody: true,
|
||||
appBar: AppBar(
|
||||
title: const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Navigáció'),
|
||||
Text(
|
||||
"Mérés: Budapest-4",
|
||||
style: TextStyle(fontSize: 12.0),
|
||||
)
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 20.0),
|
||||
child: Obx(
|
||||
() => GestureDetector(
|
||||
onTap: () {
|
||||
if (controller.gpsIsConnected.value) {
|
||||
controller.disconnectFromGps();
|
||||
} else {
|
||||
controller.connectToGps();
|
||||
}
|
||||
},
|
||||
child: Icon(Icons.gps_fixed,
|
||||
size: 26.0,
|
||||
color: controller.gpsIsConnected.value
|
||||
? Colors.green
|
||||
: Colors.red),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 20.0),
|
||||
child: Obx(
|
||||
() => GestureDetector(
|
||||
onTap: () {
|
||||
if (controller.ntripIsConnected.value) {
|
||||
controller.disconnectFromNtripServer();
|
||||
} else {
|
||||
controller.connectToNtripServer();
|
||||
}
|
||||
},
|
||||
child: Icon(
|
||||
Icons.assistant,
|
||||
size: 26.0,
|
||||
color: controller.ntripIsConnected.value
|
||||
? Colors.green
|
||||
: Colors.red,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 20.0),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
controller.ReadPointsFromFile();
|
||||
},
|
||||
child:
|
||||
const Icon(Icons.file_open, size: 26.0, color: Colors.blue),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 20.0),
|
||||
child: GestureDetector(
|
||||
onTap: () => Get.to(() => SettingsDialog(),
|
||||
transition: Transition.downToUp),
|
||||
child: const Icon(
|
||||
Icons.more_vert,
|
||||
size: 26.0,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
Obx(
|
||||
() => controller.gpsIsConnected.value
|
||||
? Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: 170.0,
|
||||
// height: 160.0,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 2.0,
|
||||
color: const Color.fromARGB(
|
||||
130, 255, 255, 255)),
|
||||
color:
|
||||
const Color.fromARGB(130, 255, 255, 255)),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"${controller.gpsDateTime} (UTC)",
|
||||
style: const TextStyle(fontSize: 10.0),
|
||||
),
|
||||
const Divider(
|
||||
height: 5.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
Text(
|
||||
"EovX: ${controller.formatEov.format(controller.eov.value.Y)}"),
|
||||
Text(
|
||||
"EovY: ${controller.formatEov.format(controller.eov.value.X)}"),
|
||||
Text("Alt: ${controller.gpsAltitude} (m)"),
|
||||
const Divider(
|
||||
height: 5.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
Text(
|
||||
"Hor. error: ${max(controller.gpsLatitudeError.value, controller.gpsLongitudeError.value)} (m)",
|
||||
style: const TextStyle(fontSize: 14.0),
|
||||
),
|
||||
Text(
|
||||
"Vert. error: ${controller.gpsAltitudeError} (m)",
|
||||
style: const TextStyle(fontSize: 14.0),
|
||||
),
|
||||
const Divider(
|
||||
height: 5.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
Text(
|
||||
"GPS quality -> ${controller.getGpsQualityIndicator(quality: controller.gpsQuality.value)} ",
|
||||
style: const TextStyle(fontSize: 8.0),
|
||||
),
|
||||
controller.ntripIsConnected.value
|
||||
? Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Divider(
|
||||
height: 5.0,
|
||||
color: Colors.black,
|
||||
),
|
||||
Text(
|
||||
"Ntrip ${controller.ntripReceivedData} byte(s) (${controller.ntripDataPacketNumbers})",
|
||||
style:
|
||||
const TextStyle(fontSize: 10.0),
|
||||
),
|
||||
Text(
|
||||
"GGA last send: ${controller.ggaSendLastTimeStr} (${controller.ggaSenDataPacketNumber})",
|
||||
style:
|
||||
const TextStyle(fontSize: 10.0),
|
||||
),
|
||||
],
|
||||
)
|
||||
: const SizedBox(
|
||||
width: 0.0,
|
||||
height: 0.0,
|
||||
)
|
||||
],
|
||||
)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
DropdownButton(
|
||||
onChanged: (int? newValue) {
|
||||
controller
|
||||
.pointsToMeasureSelectedValueChanged(
|
||||
newValue!);
|
||||
},
|
||||
items:
|
||||
controller.pointsToMeasureDropDownMenuItem,
|
||||
value: controller
|
||||
.pointsToMeasureSelectedValue.value,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
FittedBox(
|
||||
child: Text(
|
||||
'Távolság: ${(controller.distance * 1000).toStringAsFixed(3)} m',
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 12.0),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
),
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
Obx(
|
||||
() => controller.mapIsInitialized.value
|
||||
? FlutterMap(
|
||||
mapController: controller.mapController,
|
||||
options: MapOptions(
|
||||
center: LatLng(controller.currentLatitude.value,
|
||||
controller.currentLongitude.value),
|
||||
maxZoom: 25,
|
||||
zoom: controller.currentZoom.value,
|
||||
),
|
||||
children: [
|
||||
TileLayer(
|
||||
urlTemplate:
|
||||
'http://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}',
|
||||
subdomains: const ['mt0', 'mt1', 'mt2', 'mt3'],
|
||||
maxNativeZoom: 18,
|
||||
// urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
// userAgentPackageName: 'hu.app_dev.terepi_seged',
|
||||
),
|
||||
MarkerLayer(
|
||||
markers: controller.pointNotesMarker,
|
||||
),
|
||||
MarkerLayer(
|
||||
markers: controller.currentLocationMarker),
|
||||
MarkerLayer(markers: controller.parser.markers),
|
||||
MarkerLayer(
|
||||
markers: controller.pointsToMeasureMarker),
|
||||
// PolylineLayer(
|
||||
// polylines: controller.parser.polylines),
|
||||
PolyWidgetLayer(
|
||||
polyWidgets: controller.pointsToMeasureLabel)
|
||||
],
|
||||
)
|
||||
: const Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
// Obx(
|
||||
// () => controller.gpsIsConnected.value
|
||||
// ? Positioned(
|
||||
// left: 4.0,
|
||||
// top: 4.0,
|
||||
// child: Container(
|
||||
// width: 170.0,
|
||||
// // height: 160.0,
|
||||
// decoration: BoxDecoration(
|
||||
// border: Border.all(
|
||||
// width: 2.0,
|
||||
// color: const Color.fromARGB(
|
||||
// 130, 255, 255, 255)),
|
||||
// color:
|
||||
// const Color.fromARGB(130, 255, 255, 255)),
|
||||
// child: Column(
|
||||
// mainAxisAlignment: MainAxisAlignment.start,
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// Text(
|
||||
// "${controller.gpsDateTime} (UTC)",
|
||||
// style: const TextStyle(fontSize: 10.0),
|
||||
// ),
|
||||
// const Divider(
|
||||
// height: 5.0,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// Text(
|
||||
// "EovX: ${controller.formatEov.format(controller.eov.value.Y)}"),
|
||||
// Text(
|
||||
// "EovY: ${controller.formatEov.format(controller.eov.value.X)}"),
|
||||
// Text("Alt: ${controller.gpsAltitude} (m)"),
|
||||
// const Divider(
|
||||
// height: 5.0,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// Text(
|
||||
// "Hor. error: ${max(controller.gpsLatitudeError.value, controller.gpsLongitudeError.value)} (m)",
|
||||
// style: const TextStyle(fontSize: 14.0),
|
||||
// ),
|
||||
// Text(
|
||||
// "Vert. error: ${controller.gpsAltitudeError} (m)",
|
||||
// style: const TextStyle(fontSize: 14.0),
|
||||
// ),
|
||||
// const Divider(
|
||||
// height: 5.0,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// Text(
|
||||
// "GPS quality -> ${controller.getGpsQualityIndicator(quality: controller.gpsQuality.value)} ",
|
||||
// style: const TextStyle(fontSize: 8.0),
|
||||
// ),
|
||||
// controller.ntripIsConnected.value
|
||||
// ? Column(
|
||||
// crossAxisAlignment:
|
||||
// CrossAxisAlignment.start,
|
||||
// children: [
|
||||
// const Divider(
|
||||
// height: 5.0,
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// Text(
|
||||
// "Ntrip ${controller.ntripReceivedData} byte(s) (${controller.ntripDataPacketNumbers})",
|
||||
// style: const TextStyle(
|
||||
// fontSize: 10.0),
|
||||
// ),
|
||||
// Text(
|
||||
// "GGA last send: ${controller.ggaSendLastTimeStr} (${controller.ggaSenDataPacketNumber})",
|
||||
// style: const TextStyle(
|
||||
// fontSize: 10.0),
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
// : const SizedBox(
|
||||
// width: 0.0,
|
||||
// height: 0.0,
|
||||
// )
|
||||
// ],
|
||||
// )),
|
||||
// )
|
||||
// : const Positioned(
|
||||
// child: SizedBox(
|
||||
// width: 0.0,
|
||||
// height: 0.0,
|
||||
// )),
|
||||
// )
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// bottomNavigationBar: Container(
|
||||
// padding: const EdgeInsets.all(12),
|
||||
// margin: const EdgeInsets.symmetric(horizontal: 24),
|
||||
// decoration: BoxDecoration(
|
||||
// color: Colors.black.withOpacity(0.5),
|
||||
// borderRadius: const BorderRadius.all(Radius.circular(24))),
|
||||
// child: Row(
|
||||
// children: [
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// gpsTrigger.change(true);
|
||||
// Future.delayed(const Duration(seconds: 1), () {
|
||||
// gpsTrigger.change(false);
|
||||
// });
|
||||
// // controller.onBottomNavigationBarTap(0);
|
||||
// Get.to(() => const MapAddPointDialog(),
|
||||
// fullscreenDialog: true,
|
||||
// transition: Transition.downToUp,
|
||||
// duration: const Duration(milliseconds: 600));
|
||||
// },
|
||||
// child: SizedBox(
|
||||
// height: 36,
|
||||
// width: 36,
|
||||
// child: RiveAnimation.asset(
|
||||
// "assets/RiveAssets/travel_icons_pack.riv",
|
||||
// artboard: "GPS", onInit: (artboard) {
|
||||
// StateMachineController controllerRive =
|
||||
// RiveUtils.getRiveController(artboard,
|
||||
// stateMachineName: "gps_interactivity");
|
||||
// gpsTrigger = controllerRive.findSMI("active") as SMIBool;
|
||||
// }),
|
||||
// ),
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
|
||||
floatingActionButton: Wrap(
|
||||
direction: Axis.horizontal,
|
||||
children: [
|
||||
FloatingActionButton(
|
||||
onPressed: () {
|
||||
controller.mapZoomOut();
|
||||
},
|
||||
heroTag: 'ZoomOut',
|
||||
tooltip: 'Zoom out',
|
||||
child: const Icon(Icons.remove_circle_outline_rounded),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
FloatingActionButton(
|
||||
onPressed: () {
|
||||
controller.mapZoomIn();
|
||||
},
|
||||
heroTag: 'ZoomIn',
|
||||
tooltip: 'Zoom in',
|
||||
child: const Icon(Icons.add_circle_outline_rounded),
|
||||
),
|
||||
const SizedBox(width: 15.0),
|
||||
FloatingActionButton(
|
||||
onPressed: () {
|
||||
// controller.isMapMoveToCenter();
|
||||
controller.setIsMapMoveToCenter();
|
||||
},
|
||||
heroTag: 'Center map',
|
||||
tooltip: 'Center map',
|
||||
child: Obx(
|
||||
() => Icon(Icons.center_focus_strong,
|
||||
color: controller.isMapMoveToCenter.value
|
||||
? Colors.green
|
||||
: Colors.red),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 15.0,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/navigation/presentation/controllers/navigation_controller.dart';
|
||||
|
||||
class SettingsDialog extends StatelessWidget {
|
||||
final controller = Get.find<NavigationViewController>();
|
||||
SettingsDialog({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: ListView(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
controller.vehicleNumber =
|
||||
int.parse(controller.vehicleNumberController.text);
|
||||
Get.back();
|
||||
},
|
||||
icon: const Icon(Icons.close)),
|
||||
TextButton(
|
||||
style: ButtonStyle(
|
||||
overlayColor:
|
||||
MaterialStateProperty.all(Colors.transparent)),
|
||||
onPressed: () {},
|
||||
child: const Text(
|
||||
'Bezár',
|
||||
style: TextStyle(color: Colors.blue, fontSize: 14.0),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 40.0),
|
||||
child: Text(
|
||||
'Beállítások',
|
||||
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 40.0),
|
||||
child: Text(
|
||||
'GPS vevő',
|
||||
style: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
Obx(() => Column(children: [
|
||||
RadioListTile(
|
||||
title: Text('TiGNSS Rover-FF4E'),
|
||||
value: '98:CD:AC:62:FF:4E',
|
||||
groupValue: controller.gpsAddress.value,
|
||||
onChanged: (value) {
|
||||
controller.gpsAddress.value = value!;
|
||||
}),
|
||||
RadioListTile(
|
||||
title: Text('TiGNSS Rover-8BB2'),
|
||||
value: 'E8:31:CD:14:8B:B2',
|
||||
groupValue: controller.gpsAddress.value,
|
||||
onChanged: (value) {
|
||||
controller.gpsAddress.value = value!;
|
||||
;
|
||||
}),
|
||||
RadioListTile(
|
||||
title: Text('TiGNSS Rover-FF36'),
|
||||
value: '98:CD:AC:62:FF:36',
|
||||
groupValue: controller.gpsAddress.value,
|
||||
onChanged: (value) {
|
||||
controller.gpsAddress.value = value!;
|
||||
})
|
||||
])),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Divider(
|
||||
height: 5,
|
||||
),
|
||||
),
|
||||
// const SizedBox(height: 5),
|
||||
// const Padding(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 40.0),
|
||||
// child: Text(
|
||||
// 'Bemért pont azonosítója:',
|
||||
// style: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500),
|
||||
// ),
|
||||
// ),
|
||||
// const SizedBox(height: 4),
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 40),
|
||||
// child: Row(
|
||||
// children: [
|
||||
// Flexible(
|
||||
// child: TextField(
|
||||
// controller: controller.pointPrefixController,
|
||||
// decoration: const InputDecoration(
|
||||
// border: OutlineInputBorder(), labelText: 'Előtag'),
|
||||
// ),
|
||||
// ),
|
||||
// const Padding(
|
||||
// padding: EdgeInsets.symmetric(horizontal: 10.0),
|
||||
// child: Text(
|
||||
// 'Eredeti azonosító',
|
||||
// style: TextStyle(fontSize: 12.0),
|
||||
// ),
|
||||
// ),
|
||||
// Flexible(
|
||||
// child: TextField(
|
||||
// controller: controller.pointPostfixController,
|
||||
// decoration: const InputDecoration(
|
||||
// border: OutlineInputBorder(), labelText: 'Utótag'),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
const SizedBox(height: 5),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: Text(
|
||||
'Mérés iránya:',
|
||||
style: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
Obx(
|
||||
() => Column(children: [
|
||||
RadioListTile<bool>(
|
||||
title: Text('Növekvő'),
|
||||
value: true,
|
||||
groupValue: controller.pointMeasuringDirectionForward.value,
|
||||
onChanged: (value) {
|
||||
controller.pointMeasuringDirectionForward.value = value!;
|
||||
}),
|
||||
RadioListTile<bool>(
|
||||
title: Text('Csökkenő'),
|
||||
value: false,
|
||||
groupValue: controller.pointMeasuringDirectionForward.value,
|
||||
onChanged: (value) {
|
||||
controller.pointMeasuringDirectionForward.value = value!;
|
||||
})
|
||||
]),
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Divider(
|
||||
height: 5,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: Text(
|
||||
'Vibrátor:',
|
||||
style: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
enableSuggestions: false,
|
||||
autocorrect: false,
|
||||
controller: controller.vehicleNumberController,
|
||||
keyboardType: TextInputType.number,
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
labelText: 'Járműszám:',
|
||||
icon: Icon(
|
||||
Icons.numbers,
|
||||
)),
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 5),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20),
|
||||
child: Divider(
|
||||
height: 5,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: Text(
|
||||
'Ntrip szolgáltatás:',
|
||||
style: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
||||
child: Column(children: [
|
||||
SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
controller: controller.ntripUsernameController,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
labelText: 'Felhasználónév',
|
||||
icon: Icon(Icons.account_circle_rounded)),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
obscureText: true,
|
||||
enableSuggestions: false,
|
||||
autocorrect: false,
|
||||
controller: controller.ntripPasswordController,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
labelText: 'Jelszó',
|
||||
icon: Icon(
|
||||
Icons.lock,
|
||||
)),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20)
|
||||
]),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/property_list/presentations/controllers/property_list_controller.dart';
|
||||
|
||||
class PropertyListBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => PropertyListController());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class PropertyListController extends GetxController {}
|
||||
@@ -0,0 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/property_list/presentations/controllers/property_list_controller.dart';
|
||||
|
||||
class PropertyListView extends GetView<PropertyListController> {
|
||||
const PropertyListView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/rtcm_test/presentation/controllers/rtcm_test_controller.dart';
|
||||
|
||||
class RtcmTestBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => RtcmTestController());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:nmea/nmea.dart';
|
||||
import 'package:terepi_seged/eov/convert_coordinate.dart';
|
||||
import 'package:terepi_seged/eov/eov.dart';
|
||||
import 'package:terepi_seged/gnss_sentences/gngga.dart';
|
||||
import 'package:terepi_seged/gnss_sentences/gngst.dart';
|
||||
import 'package:terepi_seged/gnss_sentences/gnrmc.dart';
|
||||
|
||||
class RtcmTestController extends GetxController {
|
||||
String gpsAddress = "E8:31:CD:14:8B:B2";
|
||||
String gpsName = "TiGNSS Rover-8BB2";
|
||||
Rx<bool> gpsIsConnected = false.obs;
|
||||
RxBool ntripIsConnected = false.obs;
|
||||
RxInt ntripDataPacketNumbers = 0.obs;
|
||||
String _messageBuffer = "";
|
||||
late BluetoothConnection connection;
|
||||
late Socket socket;
|
||||
late StreamSubscription socketStreamSubscription;
|
||||
RxInt gpsReceivedData = 0.obs;
|
||||
RxBool hasGpsValidData = false.obs;
|
||||
DateTime lastGpsRefreshTime = DateTime.now();
|
||||
String utcOfPositionFix = "";
|
||||
String utcDateOfPositionFix = "";
|
||||
RxInt ntripReceivedData = 0.obs;
|
||||
final NmeaDecoder nmeaDecoder = NmeaDecoder();
|
||||
|
||||
NumberFormat formatEov = NumberFormat("##0,000.0", "hu-HU");
|
||||
NumberFormat formatWgs84Sec = NumberFormat('00.000', 'hu-HU');
|
||||
|
||||
RxDouble gpsLatitude = 0.0.obs;
|
||||
RxString gpsLatitudeDirection = "".obs;
|
||||
RxDouble gpsLongitude = 0.0.obs;
|
||||
RxString gpsLongitudeDirection = "".obs;
|
||||
RxDouble gpsAltitude = 0.0.obs;
|
||||
RxInt gpsQuality = 0.obs;
|
||||
RxDouble gpsLatitudeError = 0.0.obs;
|
||||
RxDouble gpsLongitudeError = 0.0.obs;
|
||||
RxDouble gpsAltitudeError = 0.0.obs;
|
||||
Rx<DateTime> gpsDateTime = DateTime(2000).obs;
|
||||
Rx<Eov> eov = Eov(0, 0).obs;
|
||||
RxInt latDegree = 0.obs;
|
||||
RxInt latMin = 0.obs;
|
||||
RxDouble latSec = 0.0.obs;
|
||||
RxInt longDegree = 0.obs;
|
||||
RxInt longMin = 0.obs;
|
||||
RxDouble longSec = 0.0.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
//Loading, Success, Error handle with 1 line of code
|
||||
nmeaDecoder
|
||||
..registerTalkerSentence("GGA", (line) => Gngga(raw: line))
|
||||
..registerTalkerSentence("RMC", (line) => Gnrmc(raw: line))
|
||||
..registerTalkerSentence("GST", (line) => Gngst(raw: line));
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
super.onClose();
|
||||
FlutterBluetoothSerial.instance.setPairingRequestHandler(null);
|
||||
if (gpsIsConnected.value) {
|
||||
connection.close();
|
||||
// connection = null;
|
||||
print("BluetoothTestController dispose ....");
|
||||
}
|
||||
}
|
||||
|
||||
void connectToGps() {
|
||||
if (gpsIsConnected == false) {
|
||||
BluetoothConnection.toAddress(gpsAddress).then((value) {
|
||||
connection = value;
|
||||
gpsIsConnected.value = true;
|
||||
print("GPS is connected ...");
|
||||
|
||||
connection.input!.listen(_onDataReceived);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void disconnectFromGps() {
|
||||
if (gpsIsConnected.value) {
|
||||
connection.close();
|
||||
gpsIsConnected.value = false;
|
||||
print("GPS is disconnected ....");
|
||||
}
|
||||
if (ntripIsConnected.value) {
|
||||
disconnectFromNtripServer();
|
||||
}
|
||||
}
|
||||
|
||||
void connectToNtripServer() async {
|
||||
socket = await Socket.connect(InternetAddress('3.23.52.207'), 2101,
|
||||
timeout: const Duration(seconds: 5));
|
||||
socket.asBroadcastStream;
|
||||
ntripIsConnected.value = true;
|
||||
|
||||
socket.encoding = ascii;
|
||||
print("Connected to ntrip server ....");
|
||||
|
||||
String header = "GET /KOVARIK HTTP/1.1\r\n";
|
||||
header += "User-Agent: SharpGps iter.dk\r\n";
|
||||
header += "Accept: */*\r\nConnection: close\r\n";
|
||||
header += "Authorization: Basic ${_toBase64("info@mail.app-dev.hu:")}\r\n";
|
||||
header += "Host:rtk2go.com:2101\r\n";
|
||||
header += "Ntrip-Vesrsion:Ntrip/2.0\r\n";
|
||||
header += "\r\n";
|
||||
|
||||
// listen for responses from the server
|
||||
socketStreamSubscription = socket.listen(
|
||||
// handle data from the server
|
||||
(Uint8List data) {
|
||||
// "ICY 200 OK" - first response
|
||||
final serverResponse = String.fromCharCodes(data);
|
||||
ntripReceivedData.value = data.length;
|
||||
ntripDataPacketNumbers.value++;
|
||||
if (gpsIsConnected.value) {
|
||||
if (data.length > 12) {
|
||||
connection.output.add(data);
|
||||
}
|
||||
}
|
||||
print('Server: $ntripReceivedData');
|
||||
},
|
||||
|
||||
// handle errors
|
||||
onError: (error) {
|
||||
print(error);
|
||||
socket.destroy();
|
||||
},
|
||||
|
||||
// handle server ending connection
|
||||
onDone: () async {
|
||||
print('Server left.');
|
||||
socketStreamSubscription.cancel();
|
||||
await socket.flush();
|
||||
ntripIsConnected.value = false;
|
||||
ntripReceivedData.value = 0;
|
||||
socket.destroy();
|
||||
},
|
||||
);
|
||||
|
||||
socket.add(_convertStringToUint8List(header));
|
||||
}
|
||||
|
||||
void disconnectFromNtripServer() async {
|
||||
socketStreamSubscription.cancel();
|
||||
await socket.flush();
|
||||
socket.close();
|
||||
socket.destroy();
|
||||
ntripReceivedData.value = 0;
|
||||
ntripIsConnected.value = false;
|
||||
print("Disconnect from ntrip server....");
|
||||
}
|
||||
|
||||
void _onDataReceived(Uint8List data) {
|
||||
String sentence = "";
|
||||
|
||||
print("Bluetooth received -> ${data.length} byte(s)");
|
||||
String dataString = String.fromCharCodes(data);
|
||||
int index = data.indexOf(13);
|
||||
|
||||
if (~index != 0) {
|
||||
sentence = _messageBuffer + dataString.substring(0, index);
|
||||
_messageBuffer = dataString.substring(index);
|
||||
} else {
|
||||
_messageBuffer = _messageBuffer + dataString;
|
||||
}
|
||||
|
||||
// print("Message ($count): $sentence");
|
||||
_processGnssMessage(sentence);
|
||||
}
|
||||
|
||||
String _toBase64(String str) {
|
||||
final bytes = ascii.encode(str);
|
||||
final base64Str = base64.encode(bytes);
|
||||
|
||||
return base64Str;
|
||||
}
|
||||
|
||||
Uint8List _convertStringToUint8List(String str) {
|
||||
final List<int> codeUnits = str.codeUnits;
|
||||
final Uint8List unit8List = Uint8List.fromList(codeUnits);
|
||||
return unit8List;
|
||||
}
|
||||
|
||||
void _processGnssMessage(String message) {
|
||||
LineSplitter lineSplitter = const LineSplitter();
|
||||
List<String> lines = lineSplitter.convert(message);
|
||||
|
||||
if (lines.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String line in lines) {
|
||||
if (line.trim().isEmpty) {
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("\$GNGGA")) {
|
||||
final sentence = nmeaDecoder.decode(line);
|
||||
if (sentence!.valid && sentence is Gngga) {
|
||||
hasGpsValidData.value = sentence.gpsQualityIndicator > 0;
|
||||
if (hasGpsValidData.value) {
|
||||
if (DateTime.now().difference(lastGpsRefreshTime).inSeconds >= 2) {
|
||||
lastGpsRefreshTime = DateTime.now();
|
||||
utcOfPositionFix = sentence.utcOfPositionFix;
|
||||
gpsLatitude.value = sentence.latitude;
|
||||
gpsLatitudeDirection.value = sentence.latitudeDirection;
|
||||
gpsLongitude.value = sentence.longitude;
|
||||
gpsLongitudeDirection.value = sentence.longitudeDirection;
|
||||
gpsAltitude.value = sentence.altitudeAboveMeanSeaLevel;
|
||||
gpsQuality.value = sentence.gpsQualityIndicator;
|
||||
eov.value = ConvertCoordinate.ConvertWgsToEov(
|
||||
gpsLatitude.value, gpsLongitude.value);
|
||||
latDegree.value = ConvertCoordinate.toDegree(gpsLatitude.value);
|
||||
latMin.value = ConvertCoordinate.toMinute(gpsLatitude.value);
|
||||
latSec.value = ConvertCoordinate.toSecond(gpsLatitude.value);
|
||||
longDegree.value = ConvertCoordinate.toDegree(gpsLongitude.value);
|
||||
longMin.value = ConvertCoordinate.toMinute(gpsLongitude.value);
|
||||
longSec.value = ConvertCoordinate.toSecond(gpsLongitude.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (line.startsWith("\$GNGST") && hasGpsValidData.value) {
|
||||
final sentence = nmeaDecoder.decode(line);
|
||||
if (sentence!.valid && sentence is Gngst) {
|
||||
gpsLatitudeError.value = sentence.latitudeError;
|
||||
gpsLongitudeError.value = sentence.longitudeError;
|
||||
gpsAltitudeError.value = sentence.heightError;
|
||||
}
|
||||
}
|
||||
if (line.startsWith("\$GNRMC") && hasGpsValidData.value) {
|
||||
final sentence = nmeaDecoder.decode(line);
|
||||
if (sentence!.valid && sentence is Gnrmc) {
|
||||
utcDateOfPositionFix = sentence.date;
|
||||
if (utcDateOfPositionFix.isNotEmpty && utcOfPositionFix.isNotEmpty) {
|
||||
gpsDateTime.value = DateTime(
|
||||
2000 +
|
||||
int.parse(
|
||||
"${utcDateOfPositionFix[4]}${utcDateOfPositionFix[5]}"),
|
||||
int.parse(
|
||||
"${utcDateOfPositionFix[2]}${utcDateOfPositionFix[3]}"),
|
||||
int.parse(
|
||||
"${utcDateOfPositionFix[0]}${utcDateOfPositionFix[1]}"),
|
||||
int.parse("${utcOfPositionFix[0]}${utcOfPositionFix[1]}"),
|
||||
int.parse("${utcOfPositionFix[2]}${utcOfPositionFix[3]}"),
|
||||
int.parse("${utcOfPositionFix[4]}${utcOfPositionFix[5]}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String getGpsQualityIndicator({required int quality}) {
|
||||
String qualityStr = "Invalid";
|
||||
switch (quality) {
|
||||
case 0:
|
||||
{
|
||||
qualityStr = "Invalid";
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
qualityStr = "Standard GPS (2D/3D)";
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
qualityStr = "Differential GPS";
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
qualityStr = "RTK Fix";
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
qualityStr = "RTK Float";
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
qualityStr = "Estimated (DR) Fix";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
qualityStr = "Invalid (-1)";
|
||||
}
|
||||
}
|
||||
return qualityStr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/rtcm_test/presentation/controllers/rtcm_test_controller.dart';
|
||||
|
||||
class RtcmTestView extends GetView<RtcmTestController> {
|
||||
const RtcmTestView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: Scaffold(
|
||||
extendBody: true,
|
||||
backgroundColor: Colors.black.withOpacity(0.05),
|
||||
appBar: AppBar(
|
||||
elevation: 0.0,
|
||||
title: const Text('RtcmTest'),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back_ios),
|
||||
color: Colors.white,
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
const Center(
|
||||
child: Text("RTCM teszt view"),
|
||||
),
|
||||
ListTile(
|
||||
title: Text(controller.gpsName),
|
||||
subtitle: Obx(() => controller.gpsIsConnected.value
|
||||
? const Text("Connected",
|
||||
style: TextStyle(color: Colors.green))
|
||||
: const Text(
|
||||
"Disconnected",
|
||||
style: TextStyle(color: Colors.red),
|
||||
)),
|
||||
trailing: Obx(() => ElevatedButton(
|
||||
child: Text(controller.gpsIsConnected.value
|
||||
? "Disconnect"
|
||||
: "Connect"),
|
||||
onPressed: () {
|
||||
if (controller.gpsIsConnected.value) {
|
||||
controller.disconnectFromGps();
|
||||
} else {
|
||||
controller.connectToGps();
|
||||
}
|
||||
},
|
||||
)),
|
||||
),
|
||||
ListTile(
|
||||
title: const Text("NTRIP Server (KOVARIK)"),
|
||||
subtitle: Obx(() => controller.ntripIsConnected.value
|
||||
? const Text("Connected",
|
||||
style: TextStyle(color: Colors.green))
|
||||
: const Text(
|
||||
"Disconnected",
|
||||
style: TextStyle(color: Colors.red),
|
||||
)),
|
||||
trailing: Obx(() => ElevatedButton(
|
||||
child: Text(controller.ntripIsConnected.value
|
||||
? "Disconnect"
|
||||
: "Connect"),
|
||||
onPressed: () {
|
||||
if (controller.ntripIsConnected.value) {
|
||||
controller.disconnectFromNtripServer();
|
||||
} else {
|
||||
controller.connectToNtripServer();
|
||||
}
|
||||
},
|
||||
)),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Center(
|
||||
child: Obx(() => Text(
|
||||
"Received ${controller.gpsReceivedData} byte(s) from GNSS device")))),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Center(
|
||||
child: Obx(() => Text(
|
||||
"Received ${controller.ntripReceivedData} byte(s) from ntrip server ${controller.ntripDataPacketNumbers}")))),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Center(
|
||||
child: Obx(() => Text(
|
||||
"GPS quality -> ${controller.getGpsQualityIndicator(quality: controller.gpsQuality.value)} ")))),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Center(
|
||||
child: Obx(() => Text(
|
||||
"GpsDateTime -> ${controller.gpsDateTime} (UTC)")))),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Center(
|
||||
child: Obx(() => Text(
|
||||
'Lat: ${controller.latDegree.value}°${controller.latMin.value.toString().padLeft(2, '0')}\'${controller.formatWgs84Sec.format(controller.latSec.value)}" - Long: ${controller.longDegree.value}°${controller.longMin.value.toString().padLeft(2, '0')}\'${controller.formatWgs84Sec.format(controller.longSec.value)}"')))),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Center(
|
||||
child: Obx(() => Text(
|
||||
"EovX: ${controller.formatEov.format(controller.eov.value.Y)} - EovY: ${controller.formatEov.format(controller.eov.value.X)}")))),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Center(
|
||||
child: Obx(() => Text(
|
||||
"Altitude -> ${controller.gpsAltitude} (m)")))),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Center(
|
||||
child: Obx(() => Text(
|
||||
"Hor. error: ${max(controller.gpsLatitudeError.value, controller.gpsLongitudeError.value)} (m) - Vert. error: ${controller.gpsAltitudeError} (m)"))))
|
||||
],
|
||||
)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/socket_test/presentation/controllers/socket_test_controller.dart';
|
||||
|
||||
class SocketTestBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.lazyPut(() => SocketTestController());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'package:google_sign_in/google_sign_in.dart';
|
||||
|
||||
class SocketTestController extends GetxController {
|
||||
Socket? socket;
|
||||
StreamSubscription? socketStreamSubscription;
|
||||
RxString message = ''.obs;
|
||||
|
||||
final GoogleSignIn googleSignIn =
|
||||
GoogleSignIn(scopes: ['https://www.googleapis.com/auth/drive.appdata']);
|
||||
late GoogleSignInAccount? googleSignInAccount;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
//Loading, Success, Error handle with 1 line of code
|
||||
message.value += "OnInit finished ....\n\n";
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
super.onClose();
|
||||
disconnect();
|
||||
print("SocketTestController onClose ....");
|
||||
}
|
||||
|
||||
void googleLogIn() async {
|
||||
googleSignInAccount = await googleSignIn.signIn();
|
||||
|
||||
final GoogleSignInAuthentication googleSignInAuthentication =
|
||||
await googleSignInAccount!.authentication;
|
||||
|
||||
print("AccessToken: ${googleSignInAuthentication.accessToken}");
|
||||
print("IdToken: ${googleSignInAuthentication.idToken}");
|
||||
}
|
||||
|
||||
void connect() async {
|
||||
// socket = await Socket.connect(InternetAddress('3.23.52.207'), 2101,
|
||||
// timeout: const Duration(seconds: 5));
|
||||
socket = await Socket.connect(InternetAddress('84.206.45.44'), 2101,
|
||||
timeout: const Duration(seconds: 5));
|
||||
socket?.asBroadcastStream;
|
||||
|
||||
// socket?.encoding = ascii;
|
||||
print("Connect ....");
|
||||
message.value += "Connecting to caster .... \n\n";
|
||||
// message.value += _toBase64("info@mail.app-dev.hu:") + "\r\n";
|
||||
message.value += "${_toBase64("elgi08:Laszl0stef1")}\r\n";
|
||||
|
||||
// String header = "GET /KOVARIK HTTP/1.1\r\n";
|
||||
String header = "GET /SGO_RTK3.2 HTTP/1.1\r\n";
|
||||
header += "User-Agent: SharpGps iter.dk\r\n";
|
||||
header += "Accept: */*\r\nConnection: close\r\n";
|
||||
// header += "Authorization: Basic ${_toBase64("info@mail.app-dev.hu:")}\r\n";
|
||||
header += "Authorization: Basic ${_toBase64("elgi08:Laszl0stef1")}\r\n";
|
||||
// header += "Host:rtk2go.com:2101\r\n";
|
||||
header += "Host:gnssnet.hu:2101\r\n";
|
||||
header += "Ntrip-Vesrsion:Ntrip/2.0\r\n";
|
||||
header += "\r\n";
|
||||
|
||||
// listen for responses from the server
|
||||
socketStreamSubscription = socket?.listen(
|
||||
// handle data from the server
|
||||
(Uint8List data) {
|
||||
// "ICY 200 OK" - first response
|
||||
final serverResponse = String.fromCharCodes(data);
|
||||
int length = data.length;
|
||||
print('Server: $length');
|
||||
},
|
||||
|
||||
// handle errors
|
||||
onError: (error) {
|
||||
print(error);
|
||||
socket?.destroy();
|
||||
},
|
||||
|
||||
// handle server ending connection
|
||||
onDone: () {
|
||||
print('Server left.');
|
||||
socket?.destroy();
|
||||
socket = null;
|
||||
},
|
||||
);
|
||||
|
||||
socket?.add(_convertStringToUint8List(header));
|
||||
}
|
||||
|
||||
void disconnect() async {
|
||||
if (socket != null) {
|
||||
// socket?.close();
|
||||
socketStreamSubscription?.cancel();
|
||||
await socket?.flush();
|
||||
socket?.close();
|
||||
socket?.destroy();
|
||||
socket = null;
|
||||
print("Disconnect ....");
|
||||
}
|
||||
}
|
||||
|
||||
String _toBase64(String str) {
|
||||
final bytes = ascii.encode(str);
|
||||
final base64Str = base64.encode(bytes);
|
||||
|
||||
return base64Str;
|
||||
}
|
||||
|
||||
Uint8List _convertStringToUint8List(String str) {
|
||||
final List<int> codeUnits = str.codeUnits;
|
||||
print("_convertStringToUint8List -> $codeUnits");
|
||||
print("length codeunits -> ${codeUnits.length}");
|
||||
print(
|
||||
"_convertStringToUint8List uint8list -> ${Uint8List.fromList(codeUnits)}");
|
||||
print(
|
||||
"_convertStringToUint8List uint8list length -> ${Uint8List.fromList(codeUnits).length}");
|
||||
final Uint8List unit8List = Uint8List.fromList(codeUnits);
|
||||
|
||||
return unit8List;
|
||||
}
|
||||
|
||||
String _convertUint8ListToString(Uint8List uint8list) {
|
||||
return String.fromCharCodes(uint8list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/socket_test/presentation/controllers/socket_test_controller.dart';
|
||||
|
||||
class SocketTestView extends GetView<SocketTestController> {
|
||||
const SocketTestView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
extendBody: true,
|
||||
backgroundColor: Colors.black.withOpacity(0.05),
|
||||
appBar: AppBar(
|
||||
elevation: 0.0,
|
||||
title: const Text('Socket test (Ntrip caster)'),
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.arrow_back_ios),
|
||||
color: Colors.white,
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
},
|
||||
),
|
||||
),
|
||||
body: Column(children: [
|
||||
Column(
|
||||
children: [
|
||||
const Center(
|
||||
child: Text("SocketTestView"),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
controller.googleLogIn();
|
||||
},
|
||||
child: const Text('Google log in ...')),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
print("Pressed connect ....");
|
||||
controller.connect();
|
||||
},
|
||||
child: const Text('Connect to NTRIP caster')),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
controller.disconnect();
|
||||
},
|
||||
child: const Text('Disconnect'))
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: Obx(() => Text(
|
||||
controller.message.value,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
))))
|
||||
]));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/start/presentation/controllers/start_page_controller.dart';
|
||||
|
||||
class StartPageBinding extends Bindings {
|
||||
@override
|
||||
void dependencies() {
|
||||
Get.put<StartPageController>(StartPageController());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:terepi_seged/routes/app_pages.dart';
|
||||
|
||||
class StartPageController extends GetxController {
|
||||
late PermissionStatus bluetoothStatus;
|
||||
late Directory? applicationDocumentDirectory;
|
||||
late Directory? applicationSupportDirectory;
|
||||
late List<Directory>? externalCacheDirectories;
|
||||
late Directory? externalStorageDirectory;
|
||||
late Directory? temporaryDirectory;
|
||||
late List<Directory>? externalStorageDirectoriesDocuments;
|
||||
|
||||
@override
|
||||
void onInit() async {
|
||||
applicationDocumentDirectory = await getApplicationDocumentsDirectory();
|
||||
applicationSupportDirectory = await getApplicationSupportDirectory();
|
||||
externalCacheDirectories = await getExternalCacheDirectories();
|
||||
externalStorageDirectory = await getExternalStorageDirectory();
|
||||
temporaryDirectory = await getTemporaryDirectory();
|
||||
externalStorageDirectoriesDocuments =
|
||||
await getExternalStorageDirectories(type: StorageDirectory.documents);
|
||||
|
||||
if (applicationDocumentDirectory != null) {
|
||||
log("ApplicationDocumentsDirectory: ${applicationDocumentDirectory?.path}");
|
||||
String pointsPath = '${applicationDocumentDirectory!.path}/Points/';
|
||||
bool pointsPathIsExits = await Directory(pointsPath).exists();
|
||||
if (!pointsPathIsExits) {
|
||||
await Directory(pointsPath).create(recursive: true);
|
||||
}
|
||||
File dataFile = File("$pointsPath/data.txt");
|
||||
DateTime now = DateTime.now();
|
||||
String contents =
|
||||
"Start: ${DateFormat('kk:mm:ss \n EEE d MMM').format(now)} \r\n";
|
||||
await dataFile.writeAsString(contents, mode: FileMode.append);
|
||||
log(contents);
|
||||
} else {
|
||||
log("ApplicationDocumentsDirectory: ---- NO ----}");
|
||||
}
|
||||
if (applicationSupportDirectory != null) {
|
||||
log("applicationSupportDirectory: ${applicationSupportDirectory?.path}");
|
||||
} else {
|
||||
log("applicationSupportDirectory: ---- NO ----}");
|
||||
}
|
||||
if (externalCacheDirectories!.isNotEmpty) {
|
||||
log("externalCacheDirectories: ${externalCacheDirectories!.length}");
|
||||
for (var externalCacheDirectory in externalCacheDirectories!) {
|
||||
log(" - externalCacheDirectories: ${externalCacheDirectory.path}");
|
||||
}
|
||||
} else {
|
||||
log("externalCacheDirectories: ---- NO ----}");
|
||||
}
|
||||
if (externalStorageDirectory != null) {
|
||||
print("externalStorageDirectory: ${externalStorageDirectory?.path}");
|
||||
String pointsPath = '${externalStorageDirectory!.path}/Points/';
|
||||
bool pointsPathIsExits = await Directory(pointsPath).exists();
|
||||
if (!pointsPathIsExits) {
|
||||
await Directory(pointsPath).create(recursive: true);
|
||||
}
|
||||
File dataFile = File("$pointsPath/data.txt");
|
||||
DateTime now = DateTime.now();
|
||||
String contents =
|
||||
"Start: ${DateFormat('kk:mm:ss \n EEE d MMM').format(now)} \r\n";
|
||||
await dataFile.writeAsString(contents, mode: FileMode.append);
|
||||
print(contents);
|
||||
} else {
|
||||
log("externalStorageDirectory: ---- NO ----}");
|
||||
}
|
||||
if (temporaryDirectory != null) {
|
||||
log("temporaryDirectory: ${temporaryDirectory?.path}");
|
||||
} else {
|
||||
log("temporaryDirectory: ---- NO ----}");
|
||||
}
|
||||
if (externalStorageDirectoriesDocuments!.isNotEmpty) {
|
||||
log("externalStorageDirectoriesDocuments: ${externalStorageDirectoriesDocuments!.length}");
|
||||
for (var externalStorageDirectoryDocuments
|
||||
in externalStorageDirectoriesDocuments!) {
|
||||
log(" - externalCacheDirectories: ${externalStorageDirectoryDocuments.path}");
|
||||
}
|
||||
} else {
|
||||
log("externalStorageDirectoriesDocuments: ---- NO ----}");
|
||||
}
|
||||
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() async {
|
||||
super.onReady();
|
||||
bluetoothStatus = await Permission.bluetooth.status;
|
||||
_departStartPage();
|
||||
}
|
||||
|
||||
void _departStartPage() async {
|
||||
await Future.delayed(const Duration(seconds: 5));
|
||||
Get.offAllNamed(Routes.HOME);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import 'package:animated_text_kit/animated_text_kit.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/start/presentation/controllers/start_page_controller.dart';
|
||||
|
||||
class StartPage extends GetView<StartPageController> {
|
||||
const StartPage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white54,
|
||||
body: Center(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Text('Terepi',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 32.0,
|
||||
fontWeight: FontWeight.normal,
|
||||
letterSpacing: 1.15)),
|
||||
const SizedBox(
|
||||
width: 8.0,
|
||||
),
|
||||
DefaultTextStyle(
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.normal,
|
||||
letterSpacing: 1.15),
|
||||
child: AnimatedTextKit(
|
||||
animatedTexts: [
|
||||
TypewriterAnimatedText('Segéd',
|
||||
speed: const Duration(milliseconds: 350), cursor: '')
|
||||
],
|
||||
isRepeatingAnimation: false,
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:terepi_seged/pages/bleutooth/bindings/bluetooth_bindings.dart';
|
||||
import 'package:terepi_seged/pages/bleutooth/presentation/views/bluetooth_test_view.dart';
|
||||
import 'package:terepi_seged/pages/home/bindings/home_bindings.dart';
|
||||
import 'package:terepi_seged/pages/home/presentation/views/home_view.dart';
|
||||
import 'package:terepi_seged/pages/map/bindings/map_bindings.dart';
|
||||
import 'package:terepi_seged/pages/map/presentation/views/map_add_point_dialog.dart';
|
||||
import 'package:terepi_seged/pages/map/presentation/views/map_view.dart';
|
||||
import 'package:terepi_seged/pages/measured_data/bindings/measured_data_bindings.dart';
|
||||
import 'package:terepi_seged/pages/measured_data/presentation/views/measured_data_view.dart';
|
||||
import 'package:terepi_seged/pages/navigation/bindings/navigation_bindings.dart';
|
||||
import 'package:terepi_seged/pages/navigation/presentation/views/navigation_view.dart';
|
||||
import 'package:terepi_seged/pages/property_list/bindings/property_list_bindings.dart';
|
||||
import 'package:terepi_seged/pages/property_list/presentations/views/property_list_view.dart';
|
||||
import 'package:terepi_seged/pages/rtcm_test/bindings/rtcm_test_bindings.dart';
|
||||
import 'package:terepi_seged/pages/rtcm_test/presentation/views/rtcm_test_view.dart';
|
||||
import 'package:terepi_seged/pages/socket_test/bindings/socket_test_bindings.dart';
|
||||
import 'package:terepi_seged/pages/socket_test/presentation/views/socket_test_view.dart';
|
||||
import 'package:terepi_seged/pages/start/bindings/start_page_bindings.dart';
|
||||
import 'package:terepi_seged/pages/start/presentation/views/start_page.dart';
|
||||
|
||||
import '../pages/map_test/bindings/map_test_bindings.dart';
|
||||
import '../pages/map_test/presentation/views/map_test_view.dart';
|
||||
|
||||
part 'app_routes.dart';
|
||||
|
||||
// ignore: avoid_classes_with_only_static_members
|
||||
class AppPages {
|
||||
AppPages._();
|
||||
|
||||
static const INITIAL = Routes.STARTPAGE;
|
||||
|
||||
static final routes = [
|
||||
GetPage(
|
||||
name: Routes.HOME,
|
||||
page: () => const HomeView(),
|
||||
binding: HomeBinding(),
|
||||
),
|
||||
GetPage(
|
||||
name: Routes.STARTPAGE,
|
||||
page: () => const StartPage(),
|
||||
binding: StartPageBinding()),
|
||||
GetPage(
|
||||
name: Routes.MAP, page: () => const MapView(), binding: MapBinding()),
|
||||
GetPage(
|
||||
name: Routes.BLUETOOTH,
|
||||
page: () => const BluetoothTestView(),
|
||||
binding: BluetoothTestBinding()),
|
||||
GetPage(
|
||||
name: Routes.SOCKETTEST,
|
||||
page: () => const SocketTestView(),
|
||||
binding: SocketTestBinding()),
|
||||
GetPage(
|
||||
name: Routes.RTCMTEST,
|
||||
page: () => const RtcmTestView(),
|
||||
binding: RtcmTestBinding()),
|
||||
GetPage(
|
||||
name: Routes.MAPADDPOINTDIALOG,
|
||||
page: () => const MapAddPointDialog(),
|
||||
binding: MapBinding()),
|
||||
GetPage(
|
||||
name: Routes.NAVIGATION,
|
||||
page: () => const NavigationView(),
|
||||
binding: NavigationViewBinding()),
|
||||
GetPage(
|
||||
name: Routes.MAPTEST,
|
||||
page: () => const MapTestView(),
|
||||
binding: MapTestBinding()),
|
||||
GetPage(
|
||||
name: Routes.PROPERTYLIST,
|
||||
page: () => const PropertyListView(),
|
||||
binding: PropertyListBinding()),
|
||||
GetPage(
|
||||
name: Routes.MEASUREDDATA,
|
||||
binding: MeasuredDataBinding(),
|
||||
page: () => const MeasuredDataView())
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
part of 'app_pages.dart';
|
||||
|
||||
abstract class Routes {
|
||||
Routes._();
|
||||
|
||||
static const STARTPAGE = '/start_page';
|
||||
static const HOME = '/home';
|
||||
static const TEST = '/test';
|
||||
static const BLUETOOTH = '/bluetooth_test';
|
||||
static const MAP = '/map';
|
||||
static const SOCKETTEST = '/socket_test';
|
||||
static const RTCMTEST = "/rtcm_test";
|
||||
static const NAVIGATION = "/navigation";
|
||||
static const MAPTEST = '/map_test';
|
||||
static const PROPERTYLIST = '/property_list';
|
||||
static const MEASUREDDATA = '/measured_data';
|
||||
|
||||
static const MAPADDPOINTDIALOG = "/map_add_point_dialog";
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import 'package:rive/rive.dart';
|
||||
|
||||
class RiveUtils {
|
||||
static StateMachineController getRiveController(Artboard artboard,
|
||||
{stateMachineName = "State Machine 1"}) {
|
||||
StateMachineController? controller =
|
||||
StateMachineController.fromArtboard(artboard, stateMachineName);
|
||||
artboard.addController(controller!);
|
||||
return controller;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user