Compare commits

...

14 Commits
V1.0 ... main

32 changed files with 3687 additions and 200 deletions

1
.gitignore vendored
View File

@ -69,6 +69,7 @@ unlinked_spec.ds
**/android/**/GeneratedPluginRegistrant.java
**/android/key.properties
*.jks
**/android/app/.cxx/
# iOS/XCode related
**/ios/**/*.mode1v3

View File

@ -1,4 +1,7 @@
{
"java.configuration.updateBuildConfiguration": "interactive",
"cmake.sourceDirectory": "${workspaceFolder}/linux/flutter"
"cmake.sourceDirectory": "${workspaceFolder}/linux/flutter",
"editor.wordBasedSuggestions": "off",
"editor.tabCompletion": "onlySnippets",
"editor.selectionHighlight": false
}

View File

@ -1,52 +1,34 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
id "com.google.gms.google-services"
id "com.google.firebase.crashlytics"
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
apply plugin: 'com.google.gms.google-services'
def keystoreProperties=new Properties()
def keystorePropertiesFile=rootProject.file('key.properties')
if(keystorePropertiesFile.exists()){
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
compileSdkVersion 33
ndkVersion "25.1.8937393"
namespace = "hu.app_dev.terepi_seged"
compileSdk 35
// ndkVersion "25.1.8937393"
// ndkVersion flutter.ndkVersion
ndkVersion "27.0.12077973"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
// sourceCompatibility JavaVersion.VERSION_1_8
// targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
// jvmTarget = JavaVersion.VERSION_1_8
jvmTarget = JavaVersion.VERSION_17
}
defaultConfig {
@ -55,10 +37,12 @@ android {
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
minSdkVersion 23
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
multiDexEnabled true
targetSdkVersion 35
versionCode flutter.versionCode
versionName flutter.versionName
// archivesBaseName = "terepi_seged-${versionName}-${new Date().format('yyyyMMdd-HHmm')}"
// multiDexEnabled true
}
signingConfigs {
@ -83,8 +67,7 @@ flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation platform('com.google.firebase:firebase-bom:31.3.0')
implementation 'com.google.firebase:firebase-analytics-ktx'
}
// dependencies {
// implementation platform('com.google.firebase:firebase-bom:31.3.0')
// implementation 'com.google.firebase:firebase-analytics-ktx'
// }

View File

@ -1,17 +1,3 @@
buildscript {
ext.kotlin_version = '1.8.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.3.15'
}
}
allprojects {
repositories {
google()
@ -25,6 +11,18 @@ allprojects {
}
rootProject.buildDir = '../build'
subprojects {
afterEvaluate { project ->
if (project.hasProperty('android')) {
project.android {
if (namespace == null) {
namespace project.group
}
}
}
}
}
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}

View File

@ -1,6 +1,7 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip

View File

@ -1,11 +1,27 @@
include ':app'
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.7.1" apply false
id "org.jetbrains.kotlin.android" version "2.2.0" apply false
id "com.google.gms.google-services" version "4.4.0" apply false
id "com.google.firebase.crashlytics" version "2.9.9" apply false
}
include ":app"

3
devtools_options.yaml Normal file
View File

@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:

View File

@ -0,0 +1,414 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
typedef MarkerCreationCallback = Marker Function(
LatLng point, Map<String, dynamic> properties);
typedef CircleMarkerCreationCallback = CircleMarker Function(
LatLng point, Map<String, dynamic> properties);
typedef PolylineCreationCallback = Polyline Function(
List<LatLng> points, Map<String, dynamic> properties);
typedef PolygonCreationCallback = Polygon Function(List<LatLng> points,
List<List<LatLng>>? holePointsList, Map<String, dynamic> properties);
typedef FilterFunction = bool Function(Map<String, dynamic> properties);
/// GeoJsonParser parses the GeoJson and fills three lists of parsed objects
/// which are defined in flutter_map package
/// - list of [Marker]s
/// - list of [CircleMarker]s
/// - list of [Polyline]s
/// - list of [Polygon]s
///
/// One should pass these lists when creating adequate layers in flutter_map.
/// For details see example.
///
/// Currently GeoJson parser supports only FeatureCollection and not GeometryCollection.
/// See the GeoJson Format specification at: https://www.rfc-editor.org/rfc/rfc7946
///
/// For creation of [Marker], [Polyline], [CircleMarker] and [Polygon] objects the default callback functions
/// are provided which are used in case when no user-defined callback function is provided.
/// To fully customize the [Marker], [Polyline], [CircleMarker] and [Polygon] creation one has to write his own
/// callback functions. As a template the default callback functions can be used.
///
class GeoJsonParser {
/// list of [Marker] objects created as result of parsing
final List<Marker> markers = [];
/// list of [Polyline] objects created as result of parsing
final List<Polyline> polylines = [];
/// list of [Polygon] objects created as result of parsing
final List<Polygon> polygons = [];
/// list of [CircleMarker] objects created as result of parsing
final List<CircleMarker> circles = [];
/// user defined callback function that creates a [Marker] object
MarkerCreationCallback? markerCreationCallback;
/// user defined callback function that creates a [Polyline] object
PolylineCreationCallback? polyLineCreationCallback;
/// user defined callback function that creates a [Polygon] object
PolygonCreationCallback? polygonCreationCallback;
/// user defined callback function that creates a [Polygon] object
CircleMarkerCreationCallback? circleMarkerCreationCallback;
/// default [Marker] color
Color? defaultMarkerColor;
/// default [Marker] icon
IconData? defaultMarkerIcon;
/// default [Polyline] color
Color? defaultPolylineColor;
/// default [Polyline] stroke
double? defaultPolylineStroke;
/// default [Polygon] border color
Color? defaultPolygonBorderColor;
/// default [Polygon] fill color
Color? defaultPolygonFillColor;
/// default [Polygon] border stroke
double? defaultPolygonBorderStroke;
/// default flag if [Polygon] is filled (default is true)
bool? defaultPolygonIsFilled;
/// default [CircleMarker] border color
Color? defaultCircleMarkerColor;
/// default [CircleMarker] border stroke
Color? defaultCircleMarkerBorderColor;
/// default flag if [CircleMarker] is filled (default is true)
bool? defaultCircleMarkerIsFilled;
/// user defined callback function called when the [Marker] is tapped
void Function(Map<String, dynamic>)? onMarkerTapCallback;
/// user defined callback function called when the [CircleMarker] is tapped
void Function(Map<String, dynamic>)? onCircleMarkerTapCallback;
/// user defined callback function called during parse for filtering
FilterFunction? filterFunction;
/// default constructor - all parameters are optional and can be set later with setters
GeoJsonParser({
this.markerCreationCallback,
this.polyLineCreationCallback,
this.polygonCreationCallback,
this.circleMarkerCreationCallback,
this.filterFunction,
this.defaultMarkerColor,
this.defaultMarkerIcon,
this.onMarkerTapCallback,
this.defaultPolylineColor,
this.defaultPolylineStroke,
this.defaultPolygonBorderColor,
this.defaultPolygonFillColor,
this.defaultPolygonBorderStroke,
this.defaultPolygonIsFilled,
this.defaultCircleMarkerColor,
this.defaultCircleMarkerBorderColor,
this.defaultCircleMarkerIsFilled,
this.onCircleMarkerTapCallback,
});
/// parse GeJson in [String] format
void parseGeoJsonAsString(String g) {
return parseGeoJson(jsonDecode(g) as Map<String, dynamic>);
}
/// set default [Marker] color
set setDefaultMarkerColor(Color color) {
defaultMarkerColor = color;
}
/// set default [Marker] icon
set setDefaultMarkerIcon(IconData ic) {
defaultMarkerIcon = ic;
}
/// set default [Marker] tap callback function
void setDefaultMarkerTapCallback(
Function(Map<String, dynamic> f) onTapFunction) {
onMarkerTapCallback = onTapFunction;
}
/// set default [CircleMarker] color
set setDefaultCircleMarkerColor(Color color) {
defaultCircleMarkerColor = color;
}
/// set default [CircleMarker] tap callback function
void setDefaultCircleMarkerTapCallback(
Function(Map<String, dynamic> f) onTapFunction) {
onCircleMarkerTapCallback = onTapFunction;
}
/// set default [Polyline] color
set setDefaultPolylineColor(Color color) {
defaultPolylineColor = color;
}
/// set default [Polyline] stroke
set setDefaultPolylineStroke(double stroke) {
defaultPolylineStroke = stroke;
}
/// set default [Polygon] fill color
set setDefaultPolygonFillColor(Color color) {
defaultPolygonFillColor = color;
}
/// set default [Polygon] border stroke
set setDefaultPolygonBorderStroke(double stroke) {
defaultPolygonBorderStroke = stroke;
}
/// set default [Polygon] border color
set setDefaultPolygonBorderColorStroke(Color color) {
defaultPolygonBorderColor = color;
}
/// set default [Polygon] setting whether polygon is filled
set setDefaultPolygonIsFilled(bool filled) {
defaultPolygonIsFilled = filled;
}
/// main GeoJson parsing function
void parseGeoJson(Map<String, dynamic> g) {
// set default values if they are not specified by constructor
markerCreationCallback ??= createDefaultMarker;
circleMarkerCreationCallback ??= createDefaultCircleMarker;
polyLineCreationCallback ??= createDefaultPolyline;
polygonCreationCallback ??= createDefaultPolygon;
filterFunction ??= defaultFilterFunction;
defaultMarkerColor ??= Colors.red.withOpacity(0.8);
defaultMarkerIcon ??= Icons.location_pin;
defaultPolylineColor ??= Colors.blue.withOpacity(0.8);
defaultPolylineStroke ??= 3.0;
defaultPolygonBorderColor ??= Colors.black.withOpacity(0.8);
defaultPolygonFillColor ??= Colors.black.withOpacity(0.1);
defaultPolygonIsFilled ??= true;
defaultPolygonBorderStroke ??= 1.0;
defaultCircleMarkerColor ??= Colors.blue.withOpacity(0.25);
defaultCircleMarkerBorderColor ??= Colors.black.withOpacity(0.8);
defaultCircleMarkerIsFilled ??= true;
// loop through the GeoJson Map and parse it
for (Map f in g['features'] as List) {
String geometryType = f['geometry']['type'].toString();
// check if this spatial object passes the filter function
if (!filterFunction!(f['properties'] as Map<String, dynamic>)) {
continue;
}
switch (geometryType) {
case 'Point':
{
markers.add(
markerCreationCallback!(
LatLng(f['geometry']['coordinates'][1] as double,
f['geometry']['coordinates'][0] as double),
f['properties'] as Map<String, dynamic>),
);
}
break;
case 'Circle':
{
circles.add(
circleMarkerCreationCallback!(
LatLng(f['geometry']['coordinates'][1] as double,
f['geometry']['coordinates'][0] as double),
f['properties'] as Map<String, dynamic>),
);
}
break;
case 'MultiPoint':
{
for (final point in f['geometry']['coordinates'] as List) {
markers.add(
markerCreationCallback!(
LatLng(point[1] as double, point[0] as double),
f['properties'] as Map<String, dynamic>),
);
}
}
break;
case 'LineString':
{
final List<LatLng> lineString = [];
for (final coords in f['geometry']['coordinates'] as List) {
lineString.add(LatLng(coords[1] as double, coords[0] as double));
}
polylines.add(polyLineCreationCallback!(
lineString, f['properties'] as Map<String, dynamic>));
}
break;
case 'MultiLineString':
{
for (final line in f['geometry']['coordinates'] as List) {
final List<LatLng> lineString = [];
for (final coords in line as List) {
lineString
.add(LatLng(coords[1] as double, coords[0] as double));
}
polylines.add(polyLineCreationCallback!(
lineString, f['properties'] as Map<String, dynamic>));
}
}
break;
case 'Polygon':
{
final List<LatLng> outerRing = [];
final List<List<LatLng>> holesList = [];
int pathIndex = 0;
for (final path in f['geometry']['coordinates'] as List) {
final List<LatLng> hole = [];
for (final coords in path as List<dynamic>) {
if (pathIndex == 0) {
// add to polygon's outer ring
outerRing
.add(LatLng(coords[1] as double, coords[0] as double));
} else {
// add it to current hole
hole.add(LatLng(coords[1] as double, coords[0] as double));
}
}
if (pathIndex > 0) {
// add hole to the polygon's list of holes
holesList.add(hole);
}
pathIndex++;
}
polygons.add(polygonCreationCallback!(
outerRing, holesList, f['properties'] as Map<String, dynamic>));
}
break;
case 'MultiPolygon':
{
for (final polygon in f['geometry']['coordinates'] as List) {
final List<LatLng> outerRing = [];
final List<List<LatLng>> holesList = [];
int pathIndex = 0;
for (final path in polygon as List) {
List<LatLng> hole = [];
for (final coords in path as List<dynamic>) {
if (pathIndex == 0) {
// add to polygon's outer ring
outerRing
.add(LatLng(coords[1] as double, coords[0] as double));
} else {
// add it to a hole
hole.add(LatLng(coords[1] as double, coords[0] as double));
}
}
if (pathIndex > 0) {
// add to polygon's list of holes
holesList.add(hole);
}
pathIndex++;
}
polygons.add(polygonCreationCallback!(outerRing, holesList,
f['properties'] as Map<String, dynamic>));
}
}
break;
}
}
return;
}
/// default function for creating tappable [Marker]
Widget defaultTappableMarker(Map<String, dynamic> properties,
void Function(Map<String, dynamic>) onMarkerTap) {
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: () {
onMarkerTap(properties);
},
child: Icon(defaultMarkerIcon, color: defaultMarkerColor),
),
);
}
/// default callback function for creating [Marker]
Marker createDefaultMarker(LatLng point, Map<String, dynamic> properties) {
return Marker(
point: point,
child: defaultTappableMarker(properties, markerTapped),
);
}
// /// default callback function for creating [Marker]
// Marker createDefaultMarker(LatLng point, Map<String, dynamic> properties) {
// return Marker(
// point: point,
// child: MouseRegion(
// cursor: SystemMouseCursors.click,
// child: GestureDetector(
// onTap: () {
// markerTapped(properties);
// },
// child: Icon(defaultMarkerIcon, color: defaultMarkerColor),
// ),
// ),
// width: 60,
// height: 60,
// );
// }
/// default callback function for creating [Polygon]
CircleMarker createDefaultCircleMarker(
LatLng point, Map<String, dynamic> properties) {
return CircleMarker(
point: point,
radius: properties["radius"].toDouble(),
useRadiusInMeter: true,
color: defaultCircleMarkerColor!,
borderColor: defaultCircleMarkerBorderColor!,
);
}
/// default callback function for creating [Polyline]
Polyline createDefaultPolyline(
List<LatLng> points, Map<String, dynamic> properties) {
return Polyline(
points: points,
color: defaultPolylineColor!,
strokeWidth: defaultPolylineStroke!);
}
/// default callback function for creating [Polygon]
Polygon createDefaultPolygon(List<LatLng> outerRing,
List<List<LatLng>>? holesList, Map<String, dynamic> properties) {
return Polygon(
points: outerRing,
holePointsList: holesList,
borderColor: defaultPolygonBorderColor!,
color: defaultPolygonFillColor!,
// isFilled: defaultPolygonIsFilled!,
borderStrokeWidth: defaultPolygonBorderStroke!,
);
}
/// the default filter function returns always true - therefore no filtering
bool defaultFilterFunction(Map<String, dynamic> properties) {
return true;
}
/// default callback function called when tappable [Marker] is tapped
void markerTapped(Map<String, dynamic> map) {
if (onMarkerTapCallback != null) {
onMarkerTapCallback!(map);
}
}
}

View File

@ -11,7 +11,7 @@ Future<void> main() async {
await Supabase.initialize(
url: 'https://supa.app-dev.hu',
anonKey:
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ewogICJyb2xlIjogImFub24iLAogICJpc3MiOiAic3VwYWJhc2UiLAogICJpYXQiOiAxNzExMDYyMDAwLAogICJleHAiOiAxODY4ODI4NDAwCn0.XWtP3eEysZDxXjaHHUZyyhw0n4YZo_xWUMWS5ajBcbI');
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.ewogICJyb2xlIjogImFub24iLAogICJpc3MiOiAic3VwYWJhc2UiLAogICJpYXQiOiAxNzQwMjY1MjAwLAogICJleHAiOiAxODk4MDMxNjAwCn0.4cMVfAnBLxne1lq0fm94rgtXLBJdRx-0f-E4Jd_jFwI');
runApp(const MyApp());
}

View File

@ -0,0 +1,9 @@
import 'package:get/get.dart';
import 'package:terepi_seged/pages/field_trip/presentations/controllers/field_trip_controller.dart';
class FieldTripBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => FieldTripController());
}
}

View File

@ -0,0 +1,162 @@
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_polygon_editor/polygon_editor/polygon_editor_controller.dart';
import 'package:get/get.dart';
import 'package:latlong2/latlong.dart';
class FieldTripController extends GetxController {
RxBool mapIsInitialized = false.obs;
RxBool mapInEditorMode = false.obs;
RxBool mapInPointEditorMode = false.obs;
final pointNotes = <Marker>[].obs;
final polylineNotes = <Polyline<Object>>[].obs;
final polygonNotes = <Polygon<Object>>[].obs;
late final MapController mapController;
late final MapOptions mapOptions;
late final PolygonEditorController polygonEditorController;
final PolygonLabelPlacementCalculator _labelPlacementCalculator =
const PolygonLabelPlacementCalculator.centroid();
@override
void onInit() async {
// TODO: implement onInit
super.onInit();
mapOptions = MapOptions(
onLongPress: (tapPosition, point) {
if (mapInEditorMode.value) {
polygonEditorController.addPoint(point);
}
if (mapInPointEditorMode.value) {
savePointNote(point: point);
}
},
keepAlive: true,
);
polylineNotes.add(
Polyline(
points: [
const LatLng(47.65, 19.00),
const LatLng(47.64, 19.02),
const LatLng(47.69, 19.22),
],
strokeWidth: 8,
color: const Color.fromARGB(255, 227, 238, 71),
hitValue: (
title: 'Purple Line',
subtitle: 'Nothing really special here...',
),
),
);
polygonEditorController =
PolygonEditorController(mode: PolygonEditorMode.polygon);
mapController = MapController();
mapIsInitialized.value = true;
}
@override
void dispose() {
// TODO: implement dispose
polygonEditorController.dispose();
super.dispose();
}
void cancelEditorController() {
polygonEditorController.clear();
mapInEditorMode.value = false;
}
void startPolygonEdition() {
polygonEditorController.clear();
polygonEditorController.setMode(PolygonEditorMode.polygon);
mapInEditorMode.value = true;
}
void startPolylineEdition() {
polygonEditorController.clear();
polygonEditorController.setMode(PolygonEditorMode.line);
mapInEditorMode.value = true;
}
void startPointEdition() {
mapInPointEditorMode.value = true;
}
void saveNote() {
if (polygonEditorController.mode == PolygonEditorMode.line) {
print("Points number in line: ${polygonEditorController.points.length}");
print(
"1. point coords: ${polygonEditorController.points[0].latitude} - ${polygonEditorController.points[0].longitude}");
Polyline polyline = Polyline(
points: polygonEditorController.points,
color: Colors.red,
strokeWidth: 8,
// hitValue: (
// title: 'Purple Line',
// subtitle: 'Nothing really special here...',
// ),
);
polylineNotes.add(polyline);
// polylineNotes.refresh();
print("Points number in polylineNotes: ${polylineNotes.length}");
print(
"1. point coords of polyline: ${polyline.points[0].latitude} - ${polyline.points[0].longitude}");
polygonEditorController.clear();
mapInEditorMode.value = false;
}
if (polygonEditorController.mode == PolygonEditorMode.polygon) {
print(
"Points number in polygon: ${polygonEditorController.points.length}");
Polygon polygon = Polygon(
points: polygonEditorController.points,
color: Colors.purple,
borderColor: Colors.yellow,
borderStrokeWidth: 4,
label: 'Label!',
labelPlacementCalculator: _labelPlacementCalculator,
// hitValue: (
// title: 'Basic Filled Polygon',
// subtitle: 'Nothing really special here...',
);
polygonNotes.add(polygon);
polygonNotes.refresh();
update();
print("Points number in polygonNotes: ${polygonNotes.length}");
polygonEditorController.clear();
mapInEditorMode.value = false;
}
}
void savePointNote({required LatLng point}) {
Marker marker = Marker(
point: point,
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)),
));
pointNotes.add(marker);
pointNotes.refresh();
update();
mapInPointEditorMode.value = false;
}
}

View File

@ -0,0 +1,113 @@
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_location_marker/flutter_map_location_marker.dart';
import 'package:flutter_map_polygon_editor/polygon_editor.dart';
import 'package:get/get.dart';
import 'package:latlong2/latlong.dart';
import 'package:terepi_seged/pages/field_trip/presentations/controllers/field_trip_controller.dart';
import 'package:flutter/material.dart';
class FieldTripView extends GetView<FieldTripController> {
const FieldTripView({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('Terepbejárás'),
],
)),
body: Column(
children: [
Expanded(
child: Stack(children: [
Obx(() => controller.mapIsInitialized.value
? FlutterMap(
mapController: controller.mapController,
options: controller.mapOptions,
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,
),
CurrentLocationLayer(
alignPositionOnUpdate: AlignOnUpdate.once,
),
MarkerLayer(markers: controller.pointNotes),
PolylineLayer(
polylines: controller.polylineNotes,
),
PolygonLayer(
polygons: controller.polygonNotes,
useAltRendering: true,
),
// PolylineLayer(polylines: [
// Polyline(
// points: [
// const LatLng(47.65, 19.00),
// const LatLng(47.64, 19.02),
// const LatLng(47.69, 19.22),
// ],
// strokeWidth: 8,
// color: const Color(0xFF60399E),
// hitValue: (
// title: 'Purple Line',
// subtitle: 'Nothing really special here...',
// ),
// ),
// ]),
PolygonEditor(
controller: controller.polygonEditorController,
throttleDuration: Duration.zero)
],
)
: const Center(child: CircularProgressIndicator())),
Positioned(
bottom: 3,
right: 3,
child: Row(
children: [
IconButton.filled(
iconSize: 32,
onPressed: () {
controller.startPointEdition();
},
icon: const Icon(Icons.flag)),
IconButton.filled(
iconSize: 32,
onPressed: () {
controller.startPolylineEdition();
},
icon: const Icon(Icons.polyline)),
IconButton.filled(
iconSize: 32,
onPressed: () {
controller.startPolygonEdition();
},
icon: const Icon(Icons.border_outer)),
IconButton.filled(
iconSize: 32,
onPressed: () {
controller.saveNote();
},
icon: const Icon(Icons.done)),
IconButton.filled(
iconSize: 32,
onPressed: () {
controller.cancelEditorController();
},
icon: const Icon(Icons.cancel))
],
))
]))
],
),
);
}
}

View File

@ -55,16 +55,44 @@ class HomeView extends GetView<HomeViewController> {
// child: const Text('RTCM teszt'))
],
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
TextButton(
onPressed: () async {
Get.toNamed("/field_trip");
},
child: Text('Field trip')),
// TextButton(
// onPressed: () async {
// Get.toNamed("/tracking");
// },
// child: Text('Tracking')),
TextButton(
onPressed: () async {
Get.toNamed("/map");
},
child: Text('Kitűzés'))
])),
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.flag,
label: "Kitűzés",
label: "Bemérés",
onPressed: () async {
Get.toNamed('/map');
Get.toNamed('/map_survey');
},
),
BigButtonWidget(

View File

@ -9,7 +9,7 @@ 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_geojson/flutter_map_geojson.dart';
import 'package:flutter_map_polywidget/flutter_map_polywidget.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
@ -19,6 +19,8 @@ import 'package:nmea/nmea.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart'
as permission_handler;
import 'package:share_plus/share_plus.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:terepi_seged/eov/convert_coordinate.dart';
import 'package:terepi_seged/eov/eov.dart';
import 'package:terepi_seged/gnss_sentences/gngga.dart';
@ -27,12 +29,14 @@ 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;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:terepi_seged/pages/map/presentation/views/measured_points_table_dialog.dart';
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";
RxString gpsName = "TiGNSS Rover-FF4E".obs;
// String gpsName = "TiGNSS Rover-8BB2";
static const double maxZoomValue = 25.0;
Rx<bool> gpsIsConnected = false.obs;
@ -57,6 +61,8 @@ class MapViewController extends GetxController {
DateTime.now().add(const Duration(seconds: -30));
NumberFormat formatEov = NumberFormat("##0,000.0", "hu-HU");
NumberFormat formatEovZ = NumberFormat("###0.0", "hu-HU");
NumberFormat formatAltitudeError = NumberFormat("####0.000", "hu-HU");
NumberFormat formatEovForFile = NumberFormat("#####0.0", "hu-HU");
NumberFormat formatWgs84Sec = NumberFormat('00.000', 'hu-HU');
@ -65,6 +71,7 @@ class MapViewController extends GetxController {
RxDouble gpsLongitude = 0.0.obs;
RxString gpsLongitudeDirection = "".obs;
RxDouble gpsAltitude = 0.0.obs;
RxDouble gpsGeoidSeparation = 0.0.obs;
RxInt gpsQuality = 0.obs;
RxDouble gpsLatitudeError = 0.0.obs;
RxDouble gpsLongitudeError = 0.0.obs;
@ -103,8 +110,8 @@ class MapViewController extends GetxController {
int pointId = 1;
String pointIdPrefix = "";
String pointIdPostfix = "";
String ntripUserName = "";
String ntripPassword = "";
RxString ntripUserName = "".obs;
RxString ntripPassword = "".obs;
Rx<bool> pointMeasuringDirectionForward = true.obs;
@ -115,7 +122,8 @@ class MapViewController extends GetxController {
late proj4.Projection eovProj, wgsProj;
RxBool mapIsInitialized = false.obs;
GeoJsonParser parser = GeoJsonParser(defaultMarkerColor: Colors.yellow);
// GeoJsonParser parser =
// GeoJsonParser(defaultMarkerColor: const Color.fromARGB(255, 85, 34, 49));
final CollectionReference _measuredPoints =
FirebaseFirestore.instance.collection('measuredPoints');
@ -123,6 +131,14 @@ class MapViewController extends GetxController {
// late SMIBool gpsTrigger;
// late StateMachineController riveGpsIconController;
late SharedPreferences prefs;
Rx<bool> isShowPassword = false.obs;
final passwordFieldFocusNode = FocusNode();
late AuthResponse authResponse;
late Session? session;
late User? user;
@override
void onInit() async {
super.onInit();
@ -144,6 +160,26 @@ class MapViewController extends GetxController {
..registerTalkerSentence("RMC", (line) => Gnrmc(raw: line))
..registerTalkerSentence("GST", (line) => Gngst(raw: line));
prefs = await SharedPreferences.getInstance();
authResponse = await Supabase.instance.client.auth
.signInWithPassword(email: 'test.elek.1@email.hu', password: 'demo');
session = authResponse.session;
user = authResponse.user;
Supabase.instance.client
.channel('public:TerepiSeged_Receiver')
.onPostgresChanges(
event: PostgresChangeEvent.update,
schema: 'public',
table: 'TerepiSeged_Receiver',
callback: (playload) {
var id = playload.newRecord['pointNumber'] as int;
print('Change received: ${id}');
updatePointStatus(id);
})
.subscribe();
mapController = MapController();
// riveGpsIconController = RiveUtils.getRiveController(Artboard(),
@ -154,7 +190,7 @@ class MapViewController extends GetxController {
}
@override
void onClose() {
void onClose() async {
super.onClose();
FlutterBluetoothSerial.instance.setPairingRequestHandler(null);
if (gpsIsConnected.value) {
@ -169,6 +205,10 @@ class MapViewController extends GetxController {
pointPostfixController.dispose();
ntripUsernameController.dispose();
ntripPasswordController.dispose();
await Supabase.instance.client
.channel('public:TerepiSeged_Receiver')
.unsubscribe();
}
@override
@ -200,6 +240,30 @@ class MapViewController extends GetxController {
} else {
print("No external storage permission");
}
if (prefs.containsKey('gpsAddress')) {
var address = prefs.getString('gpsAddress');
if (address != null) {
gpsAddress.value = address;
}
}
if (prefs.containsKey('gpsName')) {
var name = prefs.getString('gpsName');
if (name != null) {
gpsName.value = name;
}
}
if (prefs.containsKey('ntripUserName')) {
var userName = prefs.getString('ntripUserName');
if (userName != null) {
ntripUserName.value = userName;
}
}
if (prefs.containsKey('ntripPassword')) {
var password = prefs.getString('ntripPassword');
if (password != null) {
ntripPassword.value = password;
}
}
}
directory = await getExternalStorageDirectory();
@ -228,7 +292,7 @@ class MapViewController extends GetxController {
}
}
gpsHeightController.text = '1.7';
gpsHeightController.text = '1.8';
}
void _getInitialLocation() async {
@ -302,7 +366,9 @@ class MapViewController extends GetxController {
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 += "Authorization: Basic ${_toBase64("elgi08:Laszl0stef1")}\r\n";
header +=
"Authorization: Basic ${_toBase64("${ntripUserName.value}:${ntripPassword.value}")}\r\n";
// header += "Host:rtk2go.com:2101\r\n";
header += "Host:gnssnet.hu:2101\r\n";
header += "Ntrip-Vesrsion:Ntrip/2.0\r\n";
@ -412,6 +478,7 @@ class MapViewController extends GetxController {
gpsLongitude.value = sentence.longitude;
gpsLongitudeDirection.value = sentence.longitudeDirection;
gpsAltitude.value = sentence.altitudeAboveMeanSeaLevel;
gpsGeoidSeparation.value = sentence.geoidSeparation;
gpsQuality.value = sentence.gpsQualityIndicator;
eov.value = ConvertCoordinate.ConvertWgsToEov(
gpsLatitude.value, gpsLongitude.value);
@ -441,7 +508,7 @@ class MapViewController extends GetxController {
(DateTime.now()
.difference(lastSendTimeGgaMessage)
.inSeconds >=
30)) {
5)) {
sendGgaMessage(lastGgaMessage);
print("Send GGA message: $lastGgaMessage");
ggaSenDataPacketNumber.value++;
@ -723,6 +790,31 @@ class MapViewController extends GetxController {
"gpsHeight": gpsHeightController.text
});
await Supabase.instance.client
.from('TerepiSeged_MeasuredPoints')
.insert({
'pointNumber': pointId,
'gnssNumber': gpsName.value,
'latitude': gpsLatitude.value,
'longitude': gpsLongitude.value,
'altitude': gpsAltitude.value,
'heightOfGeoid': gpsGeoidSeparation.value,
'eovX': eov.value.X,
'eovY': eov.value.Y,
'poleHeight': double.tryParse(gpsHeightController.text),
'horizontalError':
max(gpsLatitudeError.value, gpsLongitudeError.value),
'verticalError': gpsAltitudeError.value,
'description': pointDescriptionController.text,
'isDeleted': false,
'projectId': 2
});
await Supabase.instance.client
.from('TerepiSeged_Receiver')
.update({'isMeasured': true}).eq(
'pointNumber', pointId);
if (pointMeasuringDirectionForward.isTrue) {
if (pointsToMeasureSelectedValue.value <
pointsToMeasure.length - 1) {
@ -853,6 +945,79 @@ class MapViewController extends GetxController {
}
}
void readPointsFromSupa() async {
// final AuthResponse res = await Supabase.instance.client.auth
// .signInWithPassword(email: 'test.elek.1@email.hu', password: 'demo');
// final Session? session = res.session;
// final User? user = res.user;
final data =
await Supabase.instance.client.from('TerepiSeged_Receiver').select();
print('supa count ->${data.length}');
for (int i = 0; i < data.length; i++) {
var items = data[i];
if (items.length >= 3) {
var id = items['pointNumber'];
num numEovX = items['eovX'];
var coordX = numEovX.toDouble();
num numEovY = items['eovY'];
var coordY = numEovY.toDouble();
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: i,
child: Text('$id'),
));
}
}
}
pointsToMeasureSelectedValue.value = 0;
print('Converted points number -> ${pointsToMeasure.length}');
}
void pointsToMeasureSelectedValueChanged(int value) {
pointsToMeasureSelectedValue.value = value;
print('Selected point -> ${pointsToMeasureSelectedValue.value}');
@ -887,4 +1052,101 @@ class MapViewController extends GetxController {
void showAddPointDialog() {
onBottomNavigationBarTap(0);
}
void saveGpsAddress(String address) {
prefs.setString('gpsAddress', address);
}
void saveGpsName(String name) {
prefs.setString('gpsName', name);
}
void saveNtripUserName(String username) {
prefs.setString('ntripUserName', username);
}
void saveNtripPassword(String password) {
prefs.setString('ntripPassword', password);
}
void updatePointStatus(int pointId) {}
void toggleShowPassword() {
isShowPassword.value = !isShowPassword.value;
if (passwordFieldFocusNode.hasPrimaryFocus) return;
passwordFieldFocusNode.canRequestFocus = false;
}
void showMeasuredPointsTableDialog() {
Get.to(() => MeasuredPointsTableDialog(), transition: Transition.fadeIn);
}
Future<List> readMeasuredPoints() async {
var response = await Supabase.instance.client
.from('TerepiSeged_MeasuredPoints')
.select()
.eq('projectId', 2)
.order('created_at');
print(response);
return response;
}
void SaveMeasuredPointsToFile() async {
// var pointsDirectory = await getExternalStorageDirectory();
var pointsDirectory = await getApplicationDocumentsDirectory();
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 pointsDirectory!.exists()) {
await pointsDirectory.create(recursive: true);
}
var oldMeasuredPointsFile = File("${directory!.path}/measuredsPoints.csv");
if (await oldMeasuredPointsFile.exists()) {
await oldMeasuredPointsFile.delete();
}
var measuredPointsFile =
await File("${directory!.path}/measuredsPoints.csv").create();
if (await pointsDirectory.exists()) {
if (await measuredPointsFile.exists()) {
await measuredPointsFile.writeAsString(
"Id;DateTime;Description;EovX;EovY;Altitude;Hor.Err;Vert.Err\r\n");
}
}
var data = await readMeasuredPoints();
data.forEach((d) {
measuredPointsFile.writeAsStringSync(
"${d['id']};${d['created_at']};${d['description']};${formatEov.format(d['eovY'])};${formatEov.format(d['eovX'])};${formatEovZ.format(d['altitude'] - d['poleHeight'])};${formatAltitudeError.format(d['horizontalError'])};${formatAltitudeError.format(d['verticalError'])}\r\n",
flush: true,
mode: FileMode.append,
encoding: utf8);
});
print('Number of data: ${data.length}');
final params = ShareParams(
text: "Mérési eredmények",
// files: [XFile('$measuredPointsFile')],
files: [XFile("${directory!.path}/measuredsPoints.csv")],
subject: 'Mérési eredmények',
title: 'Mérési eredmények');
final result = await SharePlus.instance.share(params);
}
}

View File

@ -30,7 +30,7 @@ class MapView extends GetView<MapViewController> {
children: [
Text('Térkép'),
Text(
"Budapest",
"",
style: TextStyle(fontSize: 12.0),
)
],
@ -89,8 +89,27 @@ class MapView extends GetView<MapViewController> {
Padding(
padding: const EdgeInsets.only(right: 20.0),
child: GestureDetector(
onTap: () => Get.to(() => SettingsDialog(),
transition: Transition.downToUp),
onTap: () {
controller.readPointsFromSupa();
},
child: const Icon(Icons.cloud_download,
size: 26.0, color: Colors.blue),
),
),
Padding(
padding: const EdgeInsets.only(right: 20.0),
child: GestureDetector(
onTap: () {
if (controller.ntripUserName.value.isNotEmpty) {
controller.ntripUsernameController.text =
controller.ntripUserName.value;
}
if (controller.ntripPassword.value.isNotEmpty) {
controller.ntripPasswordController.text =
controller.ntripPassword.value;
}
Get.to(() => SettingsDialog(), transition: Transition.downToUp);
},
child: const Icon(
Icons.more_vert,
size: 26.0,
@ -224,10 +243,11 @@ class MapView extends GetView<MapViewController> {
? FlutterMap(
mapController: controller.mapController,
options: MapOptions(
center: LatLng(controller.currentLatitude.value,
initialCenter: LatLng(
controller.currentLatitude.value,
controller.currentLongitude.value),
maxZoom: 25,
zoom: controller.currentZoom.value,
initialZoom: controller.currentZoom.value,
),
children: [
TileLayer(
@ -243,7 +263,7 @@ class MapView extends GetView<MapViewController> {
),
MarkerLayer(
markers: controller.currentLocationMarker),
MarkerLayer(markers: controller.parser.markers),
// MarkerLayer(markers: controller.parser.markers),
MarkerLayer(
markers: controller.pointsToMeasureMarker),
// PolylineLayer(
@ -438,14 +458,7 @@ class MapView extends GetView<MapViewController> {
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,
));
controller.showMeasuredPointsTableDialog();
},
heroTag: 'Database test',
tooltip: 'Pont bemérése',

View File

@ -0,0 +1,124 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:terepi_seged/pages/map/presentation/controllers/map_controller.dart';
class MeasuredPointsTableDialog extends StatelessWidget {
final controller = Get.find<MapViewController>();
MeasuredPointsTableDialog({super.key});
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(children: [
IconButton(
onPressed: () {
Get.back();
},
icon: const Icon(Icons.close)),
SizedBox(
width: 10,
),
IconButton(
onPressed: () {
controller.SaveMeasuredPointsToFile();
},
icon: const Icon(Icons.save)),
]),
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: 40.0),
child: Text(
'Bemért pontok',
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
),
const SizedBox(height: 5),
Expanded(
child: FutureBuilder<List<dynamic>>(
future: controller.readMeasuredPoints(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(
child: Text(
snapshot.error.toString(),
),
);
}
if (!snapshot.hasData) {
return const Center(
child: Text("No Data available.\n Create new Data"));
}
// print(snapshot.data);
// return const Center(child: Text("Data available."));
return ListView.builder(
itemCount: snapshot.data!.length,
shrinkWrap: true,
itemBuilder: (context, int index) {
var data = snapshot.data![index];
print("snapshot data:");
print(data);
return ListTile(
leading: CircleAvatar(
backgroundColor: const Color(0xff764abc),
child: Text((index + 1).toString())),
title: Text(data['pointNumber'].toString(),
style: TextStyle(fontWeight: FontWeight.bold)),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(data['description'],
style: TextStyle(
fontStyle: FontStyle.italic,
color: Colors.grey.shade700)),
Text(
"EovX: ${controller.formatEov.format(data['eovY'])} - EovY: ${controller.formatEov.format(data['eovX'])}",
style: TextStyle(
fontStyle: FontStyle.italic,
color: Colors.grey.shade400)),
Text(
"EovZ: ${controller.formatEovZ.format(data['altitude'] - data['poleHeight'])} (m)",
style: TextStyle(
fontStyle: FontStyle.italic,
color: Colors.grey.shade400)),
Text(
"H.hiba: ${controller.formatAltitudeError.format(data['horizontalError'])} (m) - V.hiba: ${controller.formatAltitudeError.format(data['verticalError'])} (m)",
style: TextStyle(
fontStyle: FontStyle.italic,
color: Colors.grey.shade400)),
],
));
});
},
),
)
],
),
),
);
}
}

View File

@ -6,7 +6,6 @@ class SettingsDialog extends StatelessWidget {
final controller = Get.find<MapViewController>();
SettingsDialog({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
@ -18,6 +17,19 @@ class SettingsDialog extends StatelessWidget {
children: [
IconButton(
onPressed: () {
if (controller.ntripUsernameController.text.isNotEmpty) {
controller.ntripUserName.value =
controller.ntripUsernameController.text;
controller.saveNtripUserName(
controller.ntripUsernameController.text);
if (controller
.ntripPasswordController.text.isNotEmpty) {
controller.ntripPassword.value =
controller.ntripPasswordController.text;
controller.saveNtripPassword(
controller.ntripPasswordController.text);
}
}
Get.back();
},
icon: const Icon(Icons.close)),
@ -25,7 +37,22 @@ class SettingsDialog extends StatelessWidget {
style: ButtonStyle(
overlayColor:
MaterialStateProperty.all(Colors.transparent)),
onPressed: () {},
onPressed: () {
if (controller.ntripUsernameController.text.isNotEmpty) {
controller.ntripUserName.value =
controller.ntripUsernameController.text;
controller.saveNtripUserName(
controller.ntripUsernameController.text);
if (controller
.ntripPasswordController.text.isNotEmpty) {
controller.ntripPassword.value =
controller.ntripPasswordController.text;
controller.saveNtripPassword(
controller.ntripPasswordController.text);
}
}
Get.back();
},
child: const Text(
'Bezár',
style: TextStyle(color: Colors.blue, fontSize: 14.0),
@ -48,12 +75,95 @@ class SettingsDialog extends StatelessWidget {
),
),
Obx(() => Column(children: [
RadioListTile(
title: Text('TiGNSS Rover-BE6A'),
value: '10:06:1C:97:BE:6A',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-BE6A';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-BE6A');
}),
RadioListTile(
title: Text('TiGNSS Rover-1DC6'),
value: 'E8:31:CD:16:1D:C6',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-1DC6';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-1DC6');
}),
RadioListTile(
title: Text('TiGNSS Rover-9C3A'),
value: '08:3A:8D:14:9C:3A',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-9C3A';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-9C3A');
}),
RadioListTile(
title: Text('TiGNSS Rover-72C2'),
value: '10:06:1C:97:72:C2',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-72C2';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-72C2');
}),
RadioListTile(
title: Text('TiGNSS Rover-FE16'),
value: '10:06:1C:9F:FE:16',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-FE16';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-FE16');
}),
RadioListTile(
title: Text('TiGNSS Rover-3B0A'),
value: '10:C6:1C:9E:3B:0A',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-3B0A';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-3B0A');
}),
RadioListTile(
title: Text('TiGNSS Rover-7FEA'),
value: '10:06:1C:9C:7F:EA',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-7FEA';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-7FEA');
}),
RadioListTile(
title: Text('TiGNSS Rover-A39E'),
value: '10:06:1C:97:A3:9E',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-A39E';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-A39E');
}),
RadioListTile(
title: Text('TiGNSS Rover-FF4E'),
value: '98:CD:AC:62:FF:4E',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-FF4E';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-FF4E');
}),
RadioListTile(
title: Text('TiGNSS Rover-8BB2'),
@ -61,7 +171,9 @@ class SettingsDialog extends StatelessWidget {
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
;
controller.gpsName.value = 'TiGNSS Rover-8BB2';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-8BB2');
}),
RadioListTile(
title: Text('TiGNSS Rover-FF36'),
@ -69,6 +181,9 @@ class SettingsDialog extends StatelessWidget {
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-FF36';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-FF36');
})
])),
const Padding(
@ -215,26 +330,54 @@ class SettingsDialog extends StatelessWidget {
height: 40,
child: TextField(
controller: controller.ntripUsernameController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
enableSuggestions: false,
autocorrect: false,
decoration: InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.never,
isDense: true,
filled: true,
fillColor: Colors.grey.shade300,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(12)),
labelText: 'Felhasználónév',
icon: Icon(Icons.account_circle_rounded)),
prefixIcon: 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,
)),
Obx(
() => SizedBox(
height: 40,
child: TextField(
keyboardType: TextInputType.visiblePassword,
obscureText: !controller.isShowPassword.value,
focusNode: controller.passwordFieldFocusNode,
enableSuggestions: false,
autocorrect: false,
controller: controller.ntripPasswordController,
decoration: InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.never,
isDense: true,
filled: true,
fillColor: Colors.grey.shade300,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(12)),
labelText: 'Jelszó',
prefixIcon: Icon(
Icons.lock_rounded,
size: 24,
),
suffixIcon: Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 4, 0),
child: GestureDetector(
onTap: controller.toggleShowPassword,
child: Icon(
controller.isShowPassword.value
? Icons.visibility_rounded
: Icons.visibility_off_rounded,
size: 24)))),
),
),
),
const SizedBox(height: 20)

View File

@ -0,0 +1,9 @@
import 'package:get/get.dart';
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
class MapSurveyBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => MapSurveyController());
}
}

View File

@ -0,0 +1,876 @@
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:supabase_flutter/supabase_flutter.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';
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;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:terepi_seged/pages/map_survey/presentations/views/measured_points_table_dialog.dart';
class MapSurveyController 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;
RxString gpsName = "TiGNSS Rover-FF4E".obs;
// 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 formatEovZ = NumberFormat("###0.0", "hu-HU");
NumberFormat formatAltitudeError = NumberFormat("####0.000", "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;
RxDouble gpsGeoidSeparation = 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>[];
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 = "";
RxString ntripUserName = "".obs;
RxString ntripPassword = "".obs;
Rx<bool> pointMeasuringDirectionForward = true.obs;
Rx<bool> isShowPassword = false.obs;
final passwordFieldFocusNode = FocusNode();
List? measuredPoints;
List<PointWithDescription> pointWithDescriptionList = [];
late Directory? directory;
late File dataFile;
late proj4.Projection eovProj, wgsProj;
RxBool mapIsInitialized = false.obs;
// GeoJsonParser parser =
// GeoJsonParser(defaultMarkerColor: const Color.fromARGB(255, 85, 34, 49));
final CollectionReference _measuredPoints =
FirebaseFirestore.instance.collection('measuredPoints');
// late SMIBool gpsTrigger;
// late StateMachineController riveGpsIconController;
late SharedPreferences prefs;
late AuthResponse authResponse;
late Session? session;
late User? user;
@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));
prefs = await SharedPreferences.getInstance();
authResponse = await Supabase.instance.client.auth
.signInWithPassword(email: 'test.elek.1@email.hu', password: 'demo');
session = authResponse.session;
user = authResponse.user;
Supabase.instance.client
.channel('public:TerepiSeged_Receiver')
.onPostgresChanges(
event: PostgresChangeEvent.update,
schema: 'public',
table: 'TerepiSeged_Receiver',
callback: (playload) {
var id = playload.newRecord['pointNumber'] as int;
print('Change received: ${id}');
updatePointStatus(id);
})
.subscribe();
mapController = MapController();
// riveGpsIconController = RiveUtils.getRiveController(Artboard(),
// stateMachineName: "gps_Interactivity");
// gpsTrigger = riveGpsIconController.findSMI("active");
mapIsInitialized.value = true;
}
@override
void onClose() async {
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();
await Supabase.instance.client
.channel('public:TerepiSeged_Receiver')
.unsubscribe();
}
@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");
}
if (prefs.containsKey('gpsAddress')) {
var address = prefs.getString('gpsAddress');
if (address != null) {
gpsAddress.value = address;
}
}
if (prefs.containsKey('gpsName')) {
var name = prefs.getString('gpsName');
if (name != null) {
gpsName.value = name;
}
}
if (prefs.containsKey('ntripUserName')) {
var userName = prefs.getString('ntripUserName');
if (userName != null) {
ntripUserName.value = userName;
}
}
if (prefs.containsKey('ntripPassword')) {
var password = prefs.getString('ntripPassword');
if (password != null) {
ntripPassword.value = password;
}
}
}
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.8';
}
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 +=
"Authorization: Basic ${_toBase64("${ntripUserName.value}:${ntripPassword.value}")}\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;
gpsGeoidSeparation.value = sentence.geoidSeparation;
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);
currentLatitude.value = gpsLatitude.value;
currentLongitude.value = gpsLongitude.value;
_updateCurrentLocationMarker();
lastGgaMessage = line;
if (ntripIsConnected.value &&
(DateTime.now()
.difference(lastSendTimeGgaMessage)
.inSeconds >=
5)) {
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 = 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
});
await Supabase.instance.client
.from('TerepiSeged_MeasuredPoints')
.insert({
'pointNumber': pointId,
'gnssNumber': gpsName.value,
'latitude': gpsLatitude.value,
'longitude': gpsLongitude.value,
'altitude': gpsAltitude.value,
'heightOfGeoid': gpsGeoidSeparation.value,
'eovX': eov.value.X,
'eovY': eov.value.Y,
'poleHeight': double.tryParse(gpsHeightController.text),
'horizontalError':
max(gpsLatitudeError.value, gpsLongitudeError.value),
'verticalError': gpsAltitudeError.value,
'description': pointDescriptionController.text,
'isDeleted': false,
'projectId': 2
});
await Supabase.instance.client
.from('TerepiSeged_Receiver')
.update({'isMeasured': true}).eq(
'pointNumber', pointId);
pointId++;
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 addMeasuredPoint() {
_measuredPoints.add({"id": 4001, "latitude": 46.3455, "longitude": 19.652});
}
void showAddPointDialog() {
onBottomNavigationBarTap(0);
}
void saveGpsAddress(String address) {
prefs.setString('gpsAddress', address);
}
void saveGpsName(String name) {
prefs.setString('gpsName', name);
}
void saveNtripUserName(String username) {
prefs.setString('ntripUserName', username);
}
void saveNtripPassword(String password) {
prefs.setString('ntripPassword', password);
}
void updatePointStatus(int pointId) {}
void toggleShowPassword() {
isShowPassword.value = !isShowPassword.value;
if (passwordFieldFocusNode.hasPrimaryFocus) return;
passwordFieldFocusNode.canRequestFocus = false;
}
void showMeasuredPointsTableDialog() {
Get.to(() => MeasuredPointsTableDialog(), transition: Transition.fadeIn);
}
Future<List> readMeasuredPoints() async {
var response = await Supabase.instance.client
.from('TerepiSeged_MeasuredPoints')
.select()
.eq('projectId', 2)
.order('created_at');
print(response);
return response;
}
}

View File

@ -0,0 +1,97 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
class MapAddPointDialog extends GetView<MapSurveyController> {
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();
},
),
],
)
],
),
)),
);
}
}

View File

@ -0,0 +1,423 @@
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_survey/presentations/controllers/map_survey_controller.dart';
import 'package:terepi_seged/pages/map_survey/presentations/views/settings_dialog.dart';
import 'package:terepi_seged/utils/rive_utils.dart';
import 'map_add_point_dialog.dart';
class MapSurveyView extends GetView<MapSurveyController> {
const MapSurveyView({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(
"",
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: () {
if (controller.ntripUserName.value.isNotEmpty) {
controller.ntripUsernameController.text =
controller.ntripUserName.value;
}
if (controller.ntripPassword.value.isNotEmpty) {
controller.ntripPasswordController.text =
controller.ntripPassword.value;
}
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,
)
],
)),
],
),
)
: const SizedBox(),
),
Expanded(
child: Stack(
children: [
Obx(
() => controller.mapIsInitialized.value
? FlutterMap(
mapController: controller.mapController,
options: MapOptions(
initialCenter: LatLng(
controller.currentLatitude.value,
controller.currentLongitude.value),
maxZoom: 25,
initialZoom: 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.showMeasuredPointsTableDialog();
},
heroTag: 'Database test',
tooltip: 'Pont bemérése',
child: const Icon(Icons.dataset),
),
],
),
);
}
}

View File

@ -0,0 +1,114 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
class MeasuredPointsTableDialog extends StatelessWidget {
final controller = Get.find<MapSurveyController>();
MeasuredPointsTableDialog({super.key});
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Column(
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: 40.0),
child: Text(
'Bemért pontok',
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
),
const SizedBox(height: 5),
Expanded(
child: FutureBuilder<List<dynamic>>(
future: controller.readMeasuredPoints(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(
child: Text(
snapshot.error.toString(),
),
);
}
if (!snapshot.hasData) {
return const Center(
child: Text("No Data available.\n Create new Data"));
}
// print(snapshot.data);
// return const Center(child: Text("Data available."));
return ListView.builder(
itemCount: snapshot.data!.length,
shrinkWrap: true,
itemBuilder: (context, int index) {
var data = snapshot.data![index];
print("snapshot data:");
print(data);
return ListTile(
leading: CircleAvatar(
backgroundColor: const Color(0xff764abc),
child: Text((index + 1).toString())),
title: Text(data['pointNumber'].toString(),
style: TextStyle(fontWeight: FontWeight.bold)),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(data['description'],
style: TextStyle(
fontStyle: FontStyle.italic,
color: Colors.grey.shade700)),
Text(
"EovX: ${controller.formatEov.format(data['eovY'])} - EovY: ${controller.formatEov.format(data['eovX'])}",
style: TextStyle(
fontStyle: FontStyle.italic,
color: Colors.grey.shade400)),
Text(
"EovZ: ${controller.formatEovZ.format(data['altitude'] - data['poleHeight'])} (m)",
style: TextStyle(
fontStyle: FontStyle.italic,
color: Colors.grey.shade400)),
Text(
"H.hiba: ${controller.formatAltitudeError.format(data['horizontalError'])} (m) - V.hiba: ${controller.formatAltitudeError.format(data['verticalError'])} (m)",
style: TextStyle(
fontStyle: FontStyle.italic,
color: Colors.grey.shade400)),
],
));
});
},
),
)
],
),
),
);
}
}

View File

@ -0,0 +1,390 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:terepi_seged/pages/map_survey/presentations/controllers/map_survey_controller.dart';
class SettingsDialog extends StatelessWidget {
final controller = Get.find<MapSurveyController>();
SettingsDialog({super.key});
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
onPressed: () {
if (controller.ntripUsernameController.text.isNotEmpty) {
controller.ntripUserName.value =
controller.ntripUsernameController.text;
controller.saveNtripUserName(
controller.ntripUsernameController.text);
if (controller
.ntripPasswordController.text.isNotEmpty) {
controller.ntripPassword.value =
controller.ntripPasswordController.text;
controller.saveNtripPassword(
controller.ntripPasswordController.text);
}
}
Get.back();
},
icon: const Icon(Icons.close)),
TextButton(
style: ButtonStyle(
overlayColor:
MaterialStateProperty.all(Colors.transparent)),
onPressed: () {
if (controller.ntripUsernameController.text.isNotEmpty) {
controller.ntripUserName.value =
controller.ntripUsernameController.text;
controller.saveNtripUserName(
controller.ntripUsernameController.text);
if (controller
.ntripPasswordController.text.isNotEmpty) {
controller.ntripPassword.value =
controller.ntripPasswordController.text;
controller.saveNtripPassword(
controller.ntripPasswordController.text);
}
}
Get.back();
},
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-BE6A'),
value: '10:06:1C:97:BE:6A',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-BE6A';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-BE6A');
}),
RadioListTile(
title: Text('TiGNSS Rover-1DC6'),
value: 'E8:31:CD:16:1D:C6',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-1DC6';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-1DC6');
}),
RadioListTile(
title: Text('TiGNSS Rover-9C3A'),
value: '08:3A:8D:14:9C:3A',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-9C3A';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-9C3A');
}),
RadioListTile(
title: Text('TiGNSS Rover-72C2'),
value: '10:06:1C:97:72:C2',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-72C2';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-72C2');
}),
RadioListTile(
title: Text('TiGNSS Rover-FE16'),
value: '10:06:1C:9F:FE:16',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-FE16';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-FE16');
}),
RadioListTile(
title: Text('TiGNSS Rover-3B0A'),
value: '10:C6:1C:9E:3B:0A',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-3B0A';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-3B0A');
}),
RadioListTile(
title: Text('TiGNSS Rover-7FEA'),
value: '10:06:1C:9C:7F:EA',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-7FEA';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-7FEA');
}),
RadioListTile(
title: Text('TiGNSS Rover-A39E'),
value: '10:06:1C:97:A3:9E',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-A39E';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-A39E');
}),
RadioListTile(
title: Text('TiGNSS Rover-FF4E'),
value: '98:CD:AC:62:FF:4E',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-FF4E';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-FF4E');
}),
RadioListTile(
title: Text('TiGNSS Rover-8BB2'),
value: 'E8:31:CD:14:8B:B2',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-8BB2';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-8BB2');
}),
RadioListTile(
title: Text('TiGNSS Rover-FF36'),
value: '98:CD:AC:62:FF:36',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-FF36';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-FF36');
})
])),
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,
enableSuggestions: false,
autocorrect: false,
decoration: InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.never,
isDense: true,
filled: true,
fillColor: Colors.grey.shade300,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(12)),
labelText: 'Felhasználónév',
prefixIcon: Icon(Icons.account_circle_rounded)),
),
),
const SizedBox(height: 10),
Obx(
() => SizedBox(
height: 40,
child: TextField(
keyboardType: TextInputType.visiblePassword,
obscureText: controller.isShowPassword.value,
focusNode: controller.passwordFieldFocusNode,
enableSuggestions: false,
autocorrect: false,
controller: controller.ntripPasswordController,
decoration: InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.never,
isDense: true,
filled: true,
fillColor: Colors.grey.shade300,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(12)),
labelText: 'Jelszó',
prefixIcon: Icon(
Icons.lock_rounded,
size: 24,
),
suffixIcon: Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 4, 0),
child: GestureDetector(
onTap: controller.toggleShowPassword,
child: Icon(
controller.isShowPassword.value
? Icons.visibility_rounded
: Icons.visibility_off_rounded,
size: 24)))),
),
),
),
const SizedBox(height: 20)
]),
),
],
),
);
}
}

View File

@ -9,9 +9,10 @@ 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_geojson/flutter_map_geojson.dart';
import 'package:flutter_map_polywidget/flutter_map_polywidget.dart';
import 'package:get/get.dart';
import 'package:get/get_connect/http/src/utils/utils.dart';
import 'package:intl/date_time_patterns.dart';
import 'package:intl/intl.dart';
import 'package:location/location.dart';
@ -20,6 +21,8 @@ import 'package:nmea/nmea.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart'
as permission_handler;
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:terepi_seged/controls/geojson_parser.dart';
import 'package:terepi_seged/eov/convert_coordinate.dart';
import 'package:terepi_seged/eov/eov.dart';
import 'package:terepi_seged/gnss_sentences/gngga.dart';
@ -28,12 +31,13 @@ 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;
import 'package:shared_preferences/shared_preferences.dart';
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";
RxString gpsName = "TiGNSS Rover-FF4E".obs;
// String gpsName = "TiGNSS Rover-8BB2";
static const double maxZoomValue = 25.0;
Rx<bool> gpsIsConnected = false.obs;
@ -118,10 +122,20 @@ class NavigationViewController extends GetxController {
final CollectionReference _vibratorTracker =
FirebaseFirestore.instance.collection('vibratorTracker');
DateTime lastGpsDataSaveTime = DateTime(2000, 1, 1, 0, 0, 0);
int vehicleNumber = 2;
RxInt vehicleNumber = 5.obs;
late Location internalGpsLogger;
Location internalGpsLocation = Location();
late StreamSubscription<LocationData> internalGpsLocationSubscription;
late StreamSubscription<LocationData>? internalGpsLocationSubscription;
late List<Polyline<Object>> pathLayer = [];
RxString ntripUserName = "".obs;
RxString ntripPassword = "".obs;
late SharedPreferences prefs;
late AuthResponse authResponse;
late Session? session;
late User? user;
// late SMIBool gpsTrigger;
// late StateMachineController riveGpsIconController;
@ -146,13 +160,18 @@ class NavigationViewController extends GetxController {
..registerTalkerSentence("GST", (line) => Gngst(raw: line));
mapController = MapController();
prefs = await SharedPreferences.getInstance();
authResponse = await Supabase.instance.client.auth
.signInWithPassword(email: 'test.elek.1@email.hu', password: 'demo');
session = authResponse.session;
user = authResponse.user;
// riveGpsIconController = RiveUtils.getRiveController(Artboard(),
// stateMachineName: "gps_Interactivity");
// gpsTrigger = riveGpsIconController.findSMI("active");
mapIsInitialized.value = true;
vehicleNumberController.text = vehicleNumber.toString();
}
@override
@ -175,7 +194,7 @@ class NavigationViewController extends GetxController {
// internalGpsLogTimer.cancel();
// }
internalGpsLocationSubscription.cancel();
internalGpsLocationSubscription!.cancel();
}
@override
@ -184,8 +203,8 @@ class NavigationViewController extends GetxController {
_getInitialLocation();
String data = await rootBundle.loadString('assets/Files/kozmuvek.geojson');
parser.parseGeoJsonAsString(data);
// String data = await rootBundle.loadString('assets/Files/kozmuvek.geojson');
// parser.parseGeoJsonAsString(data);
if (await permission_handler.Permission.storage.isGranted) {
print("Storage permission is ok ...");
@ -207,6 +226,37 @@ class NavigationViewController extends GetxController {
} else {
print("No external storage permission");
}
if (prefs.containsKey('gpsAddress')) {
var address = prefs.getString('gpsAddress');
if (address != null) {
gpsAddress.value = address;
}
}
if (prefs.containsKey('gpsName')) {
var name = prefs.getString('gpsName');
if (name != null) {
gpsName.value = name;
}
}
if (prefs.containsKey('ntripUserName')) {
var userName = prefs.getString('ntripUserName');
if (userName != null) {
ntripUserName.value = userName;
}
}
if (prefs.containsKey('ntripPassword')) {
var password = prefs.getString('ntripPassword');
if (password != null) {
ntripPassword.value = password;
}
}
if (prefs.containsKey('vehicleNumber')) {
var vehicleNum = prefs.getInt('vehicleNumber');
if (vehicleNum != null) {
vehicleNumber.value = vehicleNum;
}
}
vehicleNumberController.text = vehicleNumber.toString();
}
directory = await getExternalStorageDirectory();
@ -256,7 +306,7 @@ class NavigationViewController extends GetxController {
await internalGpsLocation.changeSettings(interval: 10000);
internalGpsLocationSubscription =
internalGpsLogger.onLocationChanged.listen((LocationData value) {
internalGpsLogger.onLocationChanged.listen((LocationData value) async {
double? longitude;
double? latitude;
double? accuracy;
@ -276,16 +326,29 @@ class NavigationViewController extends GetxController {
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()
// _vibratorTracker.add({
// "gpsType": 0,
// "vibratorNumber": vehicleNumber.value,
// "gpsDateTime": time,
// "latitude": latitude,
// "longitude": longitude,
// "altitude": altitude,
// "horizontalError": accuracy,
// "speed": speed,
// "createdAt": DateTime.timestamp()
// });
await Supabase.instance.client
.from('TerepiSeged_VibratorTracker')
.insert({
'gpsType': 0,
'vibratorNumber': vehicleNumber.value,
'gpsDateTime': time.toIso8601String(),
'latitude': gpsLatitude.value,
'longitude': gpsLongitude.value,
'altitude': gpsAltitude.value,
'horizontalError': accuracy,
'speed': speed
});
});
@ -581,14 +644,17 @@ class NavigationViewController extends GetxController {
if (DateTime.now().difference(lastGpsDataSaveTime).inSeconds >= 10 &&
gpsQuality.value > 0) {
lastGpsDataSaveTime = DateTime.now();
_savePositionToDatabase();
print("Save to databases: ${lastGpsDataSaveTime}");
}
}
void _savePositionToDatabase() {
void _savePositionToDatabase() async {
_vibratorTracker.add({
"gpsType": 1,
"vibratorNumber": vehicleNumber,
"vibratorNumber": vehicleNumber.value,
"gpsQuality": gpsQuality.value,
"gpsDateTime": gpsDateTime.value,
"latitude": gpsLatitude.value,
@ -601,7 +667,25 @@ class NavigationViewController extends GetxController {
"antennaHeight": double.parse(gpsHeightController.text),
"createdAt": DateTime.timestamp()
});
lastGpsDataSaveTime = DateTime.now();
final res = await Supabase.instance.client
.from('TerepiSeged_VibratorTracker')
.insert({
"gpsType": 1,
"vibratorNumber": vehicleNumber.value,
"gpsQuality": gpsQuality.value,
"gpsDateTime": gpsDateTime.value.toIso8601String(),
"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,
// "heightOfGeoid": gpsGeoidSeparation.value,
"poleHeight": double.parse(gpsHeightController.text)
}).select();
print(res);
}
String getGpsQualityIndicator({required int quality}) {
@ -896,15 +980,15 @@ class NavigationViewController extends GetxController {
width: 15.0,
height: 15.0,
decoration: BoxDecoration(
color: Colors.purple,
color: Colors.yellow,
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,
center: LatLng(wgsCoord.y + 0.0000275, wgsCoord.x + 0.0000275),
widthInMeters: 28,
heightInMeters: 28,
// constraints: const BoxConstraints(
// minWidth: 250,
// maxWidth: 350,
@ -934,6 +1018,24 @@ class NavigationViewController extends GetxController {
}
}
void ReadPathFromFile() 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()) {
String data = await file.readAsString();
parser.defaultPolylineColor = Colors.orangeAccent;
parser.defaultPolylineStroke = 5.0;
parser.parseGeoJsonAsString(data);
pathLayer = parser.polylines;
}
}
void pointsToMeasureSelectedValueChanged(int value) {
pointsToMeasureSelectedValue.value = value;
print('Selected point -> ${pointsToMeasureSelectedValue.value}');
@ -964,4 +1066,24 @@ class NavigationViewController extends GetxController {
void addMeasuredPoint() {
// _measuredPoints.add({"id": 4001, "latitude": 46.3455, "longitude": 19.652});
}
void saveGpsAddress(String address) {
prefs.setString('gpsAddress', address);
}
void saveGpsName(String name) {
prefs.setString('gpsName', name);
}
void saveNtripUserName(String username) {
prefs.setString('ntripUserName', username);
}
void saveNtripPassword(String password) {
prefs.setString('ntripPassword', password);
}
void saveVehicleNumber(int vehicleNumber) {
prefs.setInt('vehicleNumber', vehicleNumber);
print("Save vehicleNumber to prefs");
}
}

View File

@ -27,10 +27,10 @@ class NavigationView extends GetView<NavigationViewController> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Navigáció'),
Text(
"Mérés: Budapest-4",
style: TextStyle(fontSize: 12.0),
)
// Text(
// "Mérés: Zalaegerszeg",
// style: TextStyle(fontSize: 12.0),
// )
],
),
actions: [
@ -84,6 +84,16 @@ class NavigationView extends GetView<NavigationViewController> {
const Icon(Icons.file_open, size: 26.0, color: Colors.blue),
),
),
Padding(
padding: const EdgeInsets.only(right: 20.0),
child: GestureDetector(
onTap: () {
controller.ReadPathFromFile();
},
child: const Icon(Icons.line_weight_rounded,
size: 26.0, color: Colors.blue),
),
),
Padding(
padding: const EdgeInsets.only(right: 20.0),
child: GestureDetector(
@ -222,10 +232,11 @@ class NavigationView extends GetView<NavigationViewController> {
? FlutterMap(
mapController: controller.mapController,
options: MapOptions(
center: LatLng(controller.currentLatitude.value,
initialCenter: LatLng(
controller.currentLatitude.value,
controller.currentLongitude.value),
maxZoom: 25,
zoom: controller.currentZoom.value,
initialZoom: controller.currentZoom.value,
),
children: [
TileLayer(
@ -241,13 +252,14 @@ class NavigationView extends GetView<NavigationViewController> {
),
MarkerLayer(
markers: controller.currentLocationMarker),
MarkerLayer(markers: controller.parser.markers),
// MarkerLayer(markers: controller.parser.markers),
PolylineLayer(polylines: controller.pathLayer),
MarkerLayer(
markers: controller.pointsToMeasureMarker),
// PolylineLayer(
// polylines: controller.parser.polylines),
PolylineLayer(
polylines: controller.parser.polylines),
PolyWidgetLayer(
polyWidgets: controller.pointsToMeasureLabel)
polyWidgets: controller.pointsToMeasureLabel),
],
)
: const Center(child: CircularProgressIndicator()),

View File

@ -1,13 +1,13 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import 'package:terepi_seged/pages/map/presentation/controllers/map_controller.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(
@ -19,8 +19,24 @@ class SettingsDialog extends StatelessWidget {
children: [
IconButton(
onPressed: () {
controller.vehicleNumber =
int.parse(controller.vehicleNumberController.text);
if (controller.ntripUsernameController.text.isNotEmpty) {
controller.ntripUserName.value =
controller.ntripUsernameController.text;
controller.saveNtripUserName(
controller.ntripUsernameController.text);
}
if (controller.ntripPasswordController.text.isNotEmpty) {
controller.ntripPassword.value =
controller.ntripPasswordController.text;
controller.saveNtripPassword(
controller.ntripPasswordController.text);
}
if (controller.vehicleNumberController.text.isNotEmpty) {
controller.vehicleNumber.value =
int.parse(controller.vehicleNumberController.text);
controller.saveVehicleNumber(
int.parse(controller.vehicleNumberController.text));
}
Get.back();
},
icon: const Icon(Icons.close)),
@ -28,7 +44,29 @@ class SettingsDialog extends StatelessWidget {
style: ButtonStyle(
overlayColor:
MaterialStateProperty.all(Colors.transparent)),
onPressed: () {},
onPressed: () {
if (controller.ntripUsernameController.text.isNotEmpty) {
controller.ntripUserName.value =
controller.ntripUsernameController.text;
controller.saveNtripUserName(
controller.ntripUsernameController.text);
}
if (controller.ntripPasswordController.text.isNotEmpty) {
controller.ntripPassword.value =
controller.ntripPasswordController.text;
controller.saveNtripPassword(
controller.ntripPasswordController.text);
}
print(
"vehicleNumberController: ${controller.vehicleNumberController.text}");
if (controller.vehicleNumberController.text.isNotEmpty) {
controller.vehicleNumber.value =
int.parse(controller.vehicleNumberController.text);
controller.saveVehicleNumber(
int.parse(controller.vehicleNumberController.text));
}
Get.back();
},
child: const Text(
'Bezár',
style: TextStyle(color: Colors.blue, fontSize: 14.0),
@ -51,12 +89,95 @@ class SettingsDialog extends StatelessWidget {
),
),
Obx(() => Column(children: [
RadioListTile(
title: Text('TiGNSS Rover-BE6A'),
value: '10:06:1C:97:BE:6A',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-BE6A';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-BE6A');
}),
RadioListTile(
title: Text('TiGNSS Rover-1DC6'),
value: 'E8:31:CD:16:1D:C6',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-1DC6';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-1DC6');
}),
RadioListTile(
title: Text('TiGNSS Rover-9C3A'),
value: '08:3A:8D:14:9C:3A',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-9C3A';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-9C3A');
}),
RadioListTile(
title: Text('TiGNSS Rover-72C2'),
value: '10:06:1C:97:72:C2',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-72C2';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-72C2');
}),
RadioListTile(
title: Text('TiGNSS Rover-FE16'),
value: '10:06:1C:9F:FE:16',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-FE16';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-FE16');
}),
RadioListTile(
title: Text('TiGNSS Rover-3B0A'),
value: '10:C6:1C:9E:3B:0A',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-3B0A';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-3B0A');
}),
RadioListTile(
title: Text('TiGNSS Rover-7FEA'),
value: '10:06:1C:9C:7F:EA',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-7FEA';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-7FEA');
}),
RadioListTile(
title: Text('TiGNSS Rover-A39E'),
value: '10:06:1C:97:A3:9E',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-A39E';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-A39E');
}),
RadioListTile(
title: Text('TiGNSS Rover-FF4E'),
value: '98:CD:AC:62:FF:4E',
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-FF4E';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-FF4E');
}),
RadioListTile(
title: Text('TiGNSS Rover-8BB2'),
@ -64,7 +185,9 @@ class SettingsDialog extends StatelessWidget {
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
;
controller.gpsName.value = 'TiGNSS Rover-8BB2';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-8BB2');
}),
RadioListTile(
title: Text('TiGNSS Rover-FF36'),
@ -72,6 +195,9 @@ class SettingsDialog extends StatelessWidget {
groupValue: controller.gpsAddress.value,
onChanged: (value) {
controller.gpsAddress.value = value!;
controller.gpsName.value = 'TiGNSS Rover-FF36';
controller.saveGpsAddress(value);
controller.saveGpsName('TiGNSS Rover-FF36');
})
])),
const Padding(
@ -173,15 +299,7 @@ class SettingsDialog extends StatelessWidget {
)),
),
),
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(

View File

@ -0,0 +1,9 @@
import 'package:get/get.dart';
import 'package:terepi_seged/pages/tracking/presentation/controllers/tracking_controller.dart';
class TrackingBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => TrackingController());
}
}

View File

@ -0,0 +1,3 @@
import 'package:get/get.dart';
class TrackingController extends GetxController {}

View File

@ -0,0 +1,13 @@
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import '../controllers/tracking_controller.dart';
class TrackingView extends GetView<TrackingController> {
const TrackingView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container();
}
}

View File

@ -1,11 +1,15 @@
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/field_trip/bindings/field_trip_bindings.dart';
import 'package:terepi_seged/pages/field_trip/presentations/views/fiels_trip_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/map_survey/bindings/map_survey_bindings.dart';
import 'package:terepi_seged/pages/map_survey/presentations/views/mapsurvey_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';
@ -18,6 +22,8 @@ import 'package:terepi_seged/pages/socket_test/bindings/socket_test_bindings.dar
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 'package:terepi_seged/pages/tracking/bindings/tracking_bindings.dart';
import 'package:terepi_seged/pages/tracking/presentation/views/tracking_view.dart';
import '../pages/map_test/bindings/map_test_bindings.dart';
import '../pages/map_test/presentation/views/map_test_view.dart';
@ -73,6 +79,18 @@ class AppPages {
GetPage(
name: Routes.MEASUREDDATA,
binding: MeasuredDataBinding(),
page: () => const MeasuredDataView())
page: () => const MeasuredDataView()),
GetPage(
name: Routes.MAPSURVEY,
binding: MapSurveyBinding(),
page: () => const MapSurveyView()),
GetPage(
name: Routes.FIELDTRIP,
binding: FieldTripBinding(),
page: () => const FieldTripView()),
GetPage(
name: Routes.TRACKING,
binding: TrackingBinding(),
page: () => const TrackingView())
];
}

View File

@ -14,6 +14,9 @@ abstract class Routes {
static const MAPTEST = '/map_test';
static const PROPERTYLIST = '/property_list';
static const MEASUREDDATA = '/measured_data';
static const MAPSURVEY = '/map_survey';
static const FIELDTRIP = '/field_trip';
static const TRACKING = '/tracking';
static const MAPADDPOINTDIALOG = "/map_add_point_dialog";
}

View File

@ -27,43 +27,47 @@ environment:
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
cupertino_icons: ^1.0.5
flutter_map: ^6.0.1
cupertino_icons: ^1.0.8
flutter_map: ^8.2.2
flutter_map_polygon_editor: ^0.1.2
flutter_bluetooth_serial: ^0.4.0
get: ^4.6.5
latlong2: ^0.9.0
nmea: ^3.2.0
intl: ^0.17.0
location: ^4.4.0
permission_handler: ^10.2.0
flutter_map_location_marker: ^8.0.0
path_provider: ^2.0.14
rive: ^0.11.3
firebase_core: ^2.23.0
firebase_auth: ^4.4.0
cloud_firestore: ^4.13.2
firebase_storage: ^11.5.2
google_sign_in: ^6.1.0
flutter_secure_storage: ^8.0.0
googleapis: ^11.4.0
googleapis_auth: ^1.4.1
file_picker: ^6.1.1
flutter_map_geojson2: ^1.0.2
get: ^4.7.2
latlong2: ^0.9.1
nmea: ^3.3.2
intl: ^0.20.2
location: ^8.0.0
permission_handler: ^11.4.0
flutter_map_location_marker: ^10.1.0
path_provider: ^2.1.5
rive: ^0.13.20
firebase_core: ^3.12.0
firebase_auth: ^5.5.0
cloud_firestore: ^5.6.4
firebase_storage: ^12.4.3
google_sign_in: ^6.2.2
flutter_secure_storage: ^9.2.4
googleapis: ^13.2.0
googleapis_auth: ^1.6.0
file_picker: ^9.0.0
# file_picker: ^5.0.0
sqflite: ^2.2.6
google_fonts: ^4.0.3
sqflite: ^2.4.2
google_fonts: ^6.2.1
# flutter_iconpicker: ^3.2.2
animated_text_kit: ^4.2.2
package_info_plus: ^4.2.0
flutter_map_geojson: ^1.0.1
animated_text_kit: ^4.2.3
package_info_plus: ^8.2.1
# flutter_map_geojson: ^1.0.8
# geojson: ^1.0.0
syncfusion_flutter_datagrid: ^23.2.4
syncfusion_flutter_maps: ^23.2.4
syncfusion_flutter_datagrid: ^28.2.6
syncfusion_flutter_maps: ^28.2.6
proj4dart: ^2.1.0
flutter_map_polywidget: ^1.0.1
connectivity_plus: ^5.0.2
photo_view: ^0.14.0
widget_zoom: ^0.0.3
supabase_flutter: ^2.3.4
connectivity_plus: ^6.1.3
photo_view: ^0.15.0
widget_zoom: ^0.0.4
supabase_flutter: ^2.10.2
appwrite: ^20.0.0
share_plus: ^12.0.1
flutter:
sdk: flutter
@ -75,11 +79,14 @@ dev_dependencies:
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_native_splash: ^2.2.19
flutter_lints: ^2.0.0
flutter_native_splash: ^2.4.4
flutter_lints: ^5.0.0
flutter_test:
sdk: flutter
dependency_overrides:
flutter_web_auth_2: 4.1.0
flutter_native_splash:
android: true
ios: true