Save measured point to file
This commit is contained in:
parent
7e035f1414
commit
061e64fe98
414
lib/controls/geojson_parser.dart
Normal file
414
lib/controls/geojson_parser.dart
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -65,11 +65,16 @@ class HomeView extends GetView<HomeViewController> {
|
|||||||
Get.toNamed("/field_trip");
|
Get.toNamed("/field_trip");
|
||||||
},
|
},
|
||||||
child: Text('Field trip')),
|
child: Text('Field trip')),
|
||||||
|
// TextButton(
|
||||||
|
// onPressed: () async {
|
||||||
|
// Get.toNamed("/tracking");
|
||||||
|
// },
|
||||||
|
// child: Text('Tracking')),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Get.toNamed("/tracking");
|
Get.toNamed("/map");
|
||||||
},
|
},
|
||||||
child: Text('Tracking'))
|
child: Text('Kitűzés'))
|
||||||
])),
|
])),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 10.0),
|
padding: const EdgeInsets.only(top: 10.0),
|
||||||
|
|||||||
@ -29,6 +29,7 @@ import 'package:terepi_seged/models/point_to_measure.dart';
|
|||||||
import 'package:terepi_seged/models/point_with_description_model.dart';
|
import 'package:terepi_seged/models/point_with_description_model.dart';
|
||||||
import 'package:proj4dart/proj4dart.dart' as proj4;
|
import 'package:proj4dart/proj4dart.dart' as proj4;
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:terepi_seged/pages/map/presentation/views/measured_points_table_dialog.dart';
|
||||||
|
|
||||||
class MapViewController extends GetxController {
|
class MapViewController extends GetxController {
|
||||||
// String gpsAddress = "E8:31:CD:14:8B:B2";
|
// String gpsAddress = "E8:31:CD:14:8B:B2";
|
||||||
@ -59,6 +60,8 @@ class MapViewController extends GetxController {
|
|||||||
DateTime.now().add(const Duration(seconds: -30));
|
DateTime.now().add(const Duration(seconds: -30));
|
||||||
|
|
||||||
NumberFormat formatEov = NumberFormat("##0,000.0", "hu-HU");
|
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 formatEovForFile = NumberFormat("#####0.0", "hu-HU");
|
||||||
NumberFormat formatWgs84Sec = NumberFormat('00.000', 'hu-HU');
|
NumberFormat formatWgs84Sec = NumberFormat('00.000', 'hu-HU');
|
||||||
|
|
||||||
@ -128,6 +131,8 @@ class MapViewController extends GetxController {
|
|||||||
// late StateMachineController riveGpsIconController;
|
// late StateMachineController riveGpsIconController;
|
||||||
|
|
||||||
late SharedPreferences prefs;
|
late SharedPreferences prefs;
|
||||||
|
Rx<bool> isShowPassword = false.obs;
|
||||||
|
final passwordFieldFocusNode = FocusNode();
|
||||||
|
|
||||||
late AuthResponse authResponse;
|
late AuthResponse authResponse;
|
||||||
late Session? session;
|
late Session? session;
|
||||||
@ -1062,4 +1067,63 @@ class MapViewController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updatePointStatus(int pointId) {}
|
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();
|
||||||
|
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 measuredPointsFile = File("${directory!.path}/measuredsPoints.csv");
|
||||||
|
|
||||||
|
if (await pointsDirectory.exists()) {
|
||||||
|
if (!await measuredPointsFile.exists()) {
|
||||||
|
measuredPointsFile.writeAsString(
|
||||||
|
"Id;DateTime;Description;EovX;EovY;Latitude;Longitude;Altitude;Hor.Err;Vert.Err\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = await readMeasuredPoints();
|
||||||
|
|
||||||
|
data.forEach((d) {
|
||||||
|
print("Data EovX: ${d['EovX']}");
|
||||||
|
print("Data EovY: $d[EovY]");
|
||||||
|
});
|
||||||
|
|
||||||
|
print('Number of data: ${data.length}');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -458,14 +458,7 @@ class MapView extends GetView<MapViewController> {
|
|||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
// controller.isMapMoveToCenter();
|
// controller.isMapMoveToCenter();
|
||||||
// controller.addMeasuredPoint();
|
controller.showMeasuredPointsTableDialog();
|
||||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
|
||||||
content: Text(
|
|
||||||
"Fejlesztlés alatt",
|
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
backgroundColor: Colors.black54,
|
|
||||||
));
|
|
||||||
},
|
},
|
||||||
heroTag: 'Database test',
|
heroTag: 'Database test',
|
||||||
tooltip: 'Pont bemérése',
|
tooltip: 'Pont bemérése',
|
||||||
|
|||||||
@ -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)),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -330,26 +330,54 @@ class SettingsDialog extends StatelessWidget {
|
|||||||
height: 40,
|
height: 40,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: controller.ntripUsernameController,
|
controller: controller.ntripUsernameController,
|
||||||
decoration: const InputDecoration(
|
enableSuggestions: false,
|
||||||
border: OutlineInputBorder(),
|
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',
|
labelText: 'Felhasználónév',
|
||||||
icon: Icon(Icons.account_circle_rounded)),
|
prefixIcon: Icon(Icons.account_circle_rounded)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
SizedBox(
|
Obx(
|
||||||
height: 40,
|
() => SizedBox(
|
||||||
child: TextField(
|
height: 40,
|
||||||
obscureText: true,
|
child: TextField(
|
||||||
enableSuggestions: false,
|
keyboardType: TextInputType.visiblePassword,
|
||||||
autocorrect: false,
|
obscureText: !controller.isShowPassword.value,
|
||||||
controller: controller.ntripPasswordController,
|
focusNode: controller.passwordFieldFocusNode,
|
||||||
decoration: const InputDecoration(
|
enableSuggestions: false,
|
||||||
border: OutlineInputBorder(),
|
autocorrect: false,
|
||||||
labelText: 'Jelszó',
|
controller: controller.ntripPasswordController,
|
||||||
icon: Icon(
|
decoration: InputDecoration(
|
||||||
Icons.lock,
|
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)
|
const SizedBox(height: 20)
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import 'package:path_provider/path_provider.dart';
|
|||||||
import 'package:permission_handler/permission_handler.dart'
|
import 'package:permission_handler/permission_handler.dart'
|
||||||
as permission_handler;
|
as permission_handler;
|
||||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
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/convert_coordinate.dart';
|
||||||
import 'package:terepi_seged/eov/eov.dart';
|
import 'package:terepi_seged/eov/eov.dart';
|
||||||
import 'package:terepi_seged/gnss_sentences/gngga.dart';
|
import 'package:terepi_seged/gnss_sentences/gngga.dart';
|
||||||
@ -116,7 +117,7 @@ class NavigationViewController extends GetxController {
|
|||||||
late proj4.Projection eovProj, wgsProj;
|
late proj4.Projection eovProj, wgsProj;
|
||||||
RxBool mapIsInitialized = false.obs;
|
RxBool mapIsInitialized = false.obs;
|
||||||
|
|
||||||
// GeoJsonParser parser = GeoJsonParser(defaultMarkerColor: Colors.yellow);
|
GeoJsonParser parser = GeoJsonParser(defaultMarkerColor: Colors.yellow);
|
||||||
|
|
||||||
final CollectionReference _vibratorTracker =
|
final CollectionReference _vibratorTracker =
|
||||||
FirebaseFirestore.instance.collection('vibratorTracker');
|
FirebaseFirestore.instance.collection('vibratorTracker');
|
||||||
@ -1028,10 +1029,10 @@ class NavigationViewController extends GetxController {
|
|||||||
}
|
}
|
||||||
if (await file!.exists()) {
|
if (await file!.exists()) {
|
||||||
String data = await file.readAsString();
|
String data = await file.readAsString();
|
||||||
// parser.defaultPolylineColor = Colors.orangeAccent;
|
parser.defaultPolylineColor = Colors.orangeAccent;
|
||||||
// parser.defaultPolylineStroke = 5.0;
|
parser.defaultPolylineStroke = 5.0;
|
||||||
// parser.parseGeoJsonAsString(data);
|
parser.parseGeoJsonAsString(data);
|
||||||
// pathLayer = parser.polylines;
|
pathLayer = parser.polylines;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -256,8 +256,8 @@ class NavigationView extends GetView<NavigationViewController> {
|
|||||||
PolylineLayer(polylines: controller.pathLayer),
|
PolylineLayer(polylines: controller.pathLayer),
|
||||||
MarkerLayer(
|
MarkerLayer(
|
||||||
markers: controller.pointsToMeasureMarker),
|
markers: controller.pointsToMeasureMarker),
|
||||||
// PolylineLayer(
|
PolylineLayer(
|
||||||
// polylines: controller.parser.polylines),
|
polylines: controller.parser.polylines),
|
||||||
PolyWidgetLayer(
|
PolyWidgetLayer(
|
||||||
polyWidgets: controller.pointsToMeasureLabel),
|
polyWidgets: controller.pointsToMeasureLabel),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -31,6 +31,7 @@ dependencies:
|
|||||||
flutter_map: ^8.2.2
|
flutter_map: ^8.2.2
|
||||||
flutter_map_polygon_editor: ^0.1.2
|
flutter_map_polygon_editor: ^0.1.2
|
||||||
flutter_bluetooth_serial: ^0.4.0
|
flutter_bluetooth_serial: ^0.4.0
|
||||||
|
flutter_map_geojson2: ^1.0.2
|
||||||
get: ^4.7.2
|
get: ^4.7.2
|
||||||
latlong2: ^0.9.1
|
latlong2: ^0.9.1
|
||||||
nmea: ^3.3.2
|
nmea: ^3.3.2
|
||||||
@ -66,6 +67,7 @@ dependencies:
|
|||||||
widget_zoom: ^0.0.4
|
widget_zoom: ^0.0.4
|
||||||
supabase_flutter: ^2.10.2
|
supabase_flutter: ^2.10.2
|
||||||
appwrite: ^20.0.0
|
appwrite: ^20.0.0
|
||||||
|
# share_plus: ^12.0.1
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user