Skip to content
Snippets Groups Projects
Commit f36a162f authored by Sara Savanovic Djordjevic's avatar Sara Savanovic Djordjevic
Browse files

update: marker_data classes

parent c9f7ea29
No related branches found
No related tags found
No related merge requests found
...@@ -3,3 +3,6 @@ ...@@ -3,3 +3,6 @@
# Auto-generated by Android Studio # Auto-generated by Android Studio
.idea/ .idea/
# Python interpereter
venv/
\ No newline at end of file
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'widgets/map_widget.dart'; import 'widgets/map_widget.dart';
import 'marker_data.dart'; import 'marker_handler/marker_data.dart';
import 'consts.dart'; import 'consts.dart';
import 'marker_handler/get_markers.dart';
class DefaultPage extends StatefulWidget { class DefaultPage extends StatefulWidget {
const DefaultPage({super.key}); const DefaultPage({super.key});
...@@ -16,45 +15,27 @@ class DefaultPage extends StatefulWidget { ...@@ -16,45 +15,27 @@ class DefaultPage extends StatefulWidget {
class _DefaultPageState extends State<DefaultPage> { class _DefaultPageState extends State<DefaultPage> {
late Timer _timer; late Timer _timer;
List<MarkerTemplate> markerList = []; List<Measurement> markerList = [];
// fetchMarkerTemplate requests data from the update_map endpoint // Call fetchMarkerTemplate and await its result before setting the state
Future<void> fetchMarkerTemplate() async { Future<void> loadMarkerList() async {
try { try {
// Custom HTTP client List<Measurement> fetchedMarkers = await fetchMarkerData();
HttpClient client = HttpClient()
..badCertificateCallback = // NB: temporary disable SSL certificate validation
(X509Certificate cert, String host, int port) => true;
// Request makers from API and wait for response
var request = await client.getUrl(Uri.parse(serverURI + mapEndpoint));
var response = await request.close();
// Attempt to parse json if request is ok
if (response.statusCode == 200) {
var responseBody = await response.transform(utf8.decoder).join();
setState(() { setState(() {
// Parse JSON string from response body markerList = fetchedMarkers;
List<dynamic> jsonData = json.decode(responseBody);
// Convert response from type List<dynamic> to List<MarkerTemplate>
markerList =
jsonData.map((data) => MarkerTemplate.fromJson(data)).toList();
}); });
} else {
print('Request failed with status: ${response.statusCode}');
}
} catch (e) { } catch (e) {
showDialog( showDialog(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return AlertDialog( return AlertDialog(
title: Text("Error"), title: Text("Error"),
content: Text("Failed to connect to the server. Please check your network connection"), content: Text(e.toString()),
actions: [ actions: [
TextButton( TextButton(
onPressed: () { onPressed: () {
Navigator.of(context).pop(); // Close the dialog Navigator.of(context).pop();
}, },
child: Text("OK"), child: Text("OK"),
), ),
...@@ -69,13 +50,13 @@ class _DefaultPageState extends State<DefaultPage> { ...@@ -69,13 +50,13 @@ class _DefaultPageState extends State<DefaultPage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// Call fetchMarkerTemplate when the widget is first created // Load marker data from server
fetchMarkerTemplate(); loadMarkerList();
// Schedule fetchMarkerTemplate to run periodically based on fetchInterval const // Schedule fetchMarkerTemplate to run periodically based on fetchInterval const
const Duration fiveMinutes = Duration(minutes: fetchInterval); const Duration interval = Duration(minutes: fetchInterval);
_timer = Timer.periodic(fiveMinutes, (timer) { _timer = Timer.periodic(interval, (timer) {
fetchMarkerTemplate(); fetchMarkerData();
}); });
} }
......
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import '../consts.dart';
import 'marker_data.dart';
// fetchMarkerTemplate requests all marker data from the server
Future<List<Measurement>> fetchMarkerData() async {
try {
HttpClient client = HttpClient()
..badCertificateCallback = (X509Certificate cert, String host, int port) => true;
var request = await client.getUrl(Uri.parse(serverURI + mapEndpoint));
var response = await request.close();
if (response.statusCode == 200) {
var responseBody = await response.transform(utf8.decoder).join();
List<dynamic> jsonData = json.decode(responseBody);
return jsonData.map((data) => Measurement.Measurement(data)).toList();
} else {
print('Request failed with status: ${response.statusCode}');
// Throw an exception or return null if the request fails
throw Exception('Failed to fetch marker template');
}
} catch (e) {
print('Error: $e');
// Throw an exception or return null if there's an error
throw Exception('Failed to connect to the server. Please check your network connection');
}
}
import 'package:flutter/material.dart'; class Measurement {
import 'package:latlong2/latlong.dart'; int measurementID;
int timeMeasured;
// Sensor holds data about a single sensor Sensor sensor;
class Sensor { List<Data> dataList;
int id;
String type;
bool active;
Sensor({required this.id, required this.type, required this.active}); Measurement({
required this.measurementID,
required this.timeMeasured,
required this.sensor,
required this.dataList,
});
factory Sensor.fromJson(Map<String, dynamic> json) { factory Measurement.Measurement(Map<String, dynamic> json) {
return Sensor( return Measurement(
id: json['ID'], measurementID: json['MeasurementID'],
type: json['type'], timeMeasured: json['TimeMeasured'],
active: json['active'], sensor: Sensor.fromJson(json['Sensor']),
dataList: (json['Data'] as List<dynamic>)
.map((data) => Data.fromJson(data))
.toList(),
); );
} }
} }
// DateAndTime holds the date and time for a single measurement class Sensor {
class DateAndTime { int sensorID;
int year; String sensorType;
int month; bool active;
int day;
int hour;
int minute;
DateAndTime({ Sensor({
required this.year, required this.sensorID,
required this.month, required this.sensorType,
required this.day, required this.active,
required this.hour,
required this.minute,
}); });
factory DateAndTime.fromJson(Map<String, dynamic> json) { factory Sensor.fromJson(Map<String, dynamic> json) {
return DateAndTime( return Sensor(
year: json['year'], sensorID: json['SensorID'],
month: json['month'], sensorType: json['SensorType'],
day: json['day'], active: json['Active'],
hour: json['hour'],
minute: json['minute'],
); );
} }
} }
// Measurement holds data related to a singular measurement taken class Data {
// at a given time
class Measurement {
double longitude;
double latitude; double latitude;
DateAndTime datetime; double longitude;
Sensor sensor; double iceTop;
double precipitation; double iceBottom;
double thickness; double calculatedThickness;
double maxWeight;
double safetyLevel;
double accuracy; double accuracy;
Measurement({ Data({
required this.longitude,
required this.latitude, required this.latitude,
required this.datetime, required this.longitude,
required this.sensor, required this.iceTop,
required this.precipitation, required this.iceBottom,
required this.thickness, required this.calculatedThickness,
required this.maxWeight,
required this.safetyLevel,
required this.accuracy, required this.accuracy,
}); });
factory Measurement.fromJson(Map<String, dynamic> json) { factory Data.fromJson(Map<String, dynamic> json) {
return Measurement( return Data(
longitude: json['longitude'], latitude: json['Latitude'],
latitude: json['latitude'], longitude: json['Longitude'],
datetime: DateAndTime.fromJson(json['datetime']), iceTop: json['IceTop'],
sensor: Sensor.fromJson(json['sensor']), iceBottom: json['IceBottom'],
precipitation: json['precipitation'], calculatedThickness: json['CalculatedThickness'],
thickness: json['thickness'], accuracy: json['Accuracy'],
maxWeight: json['max_weight'],
safetyLevel: json['safety_level'],
accuracy: json['accuracy'],
); );
} }
} }
\ No newline at end of file
// MarkerTemplate holds all data required for rendering a marker
class MarkerTemplate {
Measurement geoData;
LatLng location;
double size;
Color color;
MarkerTemplate({
required this.geoData,
required this.location,
required this.size,
required this.color
});
factory MarkerTemplate.fromJson(Map<String, dynamic> json) {
// Parse from JSON string to type Color
Color parsedColor = parseColor(json['color']);
return MarkerTemplate(
geoData: Measurement.fromJson(json['geo_data']),
location: LatLng(json['latitude'], json['longitude']),
size: json['size'],
color: parsedColor,
);
}
// parseColor parses the color strings into Colors types
static Color parseColor(String colorString) {
colorString = colorString.toLowerCase();
switch (colorString) {
case 'yellow':
return Colors.yellow;
case 'red':
return Colors.red;
case 'green':
return Colors.green;
default:
return Colors.black; // Default color if unrecognized
}
}
}
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../marker_data.dart'; import '../marker_handler/marker_data.dart';
import '../consts.dart'; import '../consts.dart';
import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart'; import 'package:latlong2/latlong.dart';
...@@ -8,7 +8,7 @@ import 'quick_view_chart.dart'; ...@@ -8,7 +8,7 @@ import 'quick_view_chart.dart';
import 'stat_charts.dart'; import 'stat_charts.dart';
class MapContainerWidget extends StatefulWidget { class MapContainerWidget extends StatefulWidget {
final List<MarkerTemplate> markerList; final List<Measurement> markerList;
const MapContainerWidget({Key? key, required this.markerList}) : super(key: key); const MapContainerWidget({Key? key, required this.markerList}) : super(key: key);
...@@ -18,7 +18,7 @@ class MapContainerWidget extends StatefulWidget { ...@@ -18,7 +18,7 @@ class MapContainerWidget extends StatefulWidget {
class _MapContainerWidgetState extends State<MapContainerWidget> { class _MapContainerWidgetState extends State<MapContainerWidget> {
MarkerTemplate? selectedMarker; Measurement? selectedMarker;
bool isMinimized = true; // Quick view box state tacker bool isMinimized = true; // Quick view box state tacker
@override @override
...@@ -31,83 +31,12 @@ class _MapContainerWidgetState extends State<MapContainerWidget> { ...@@ -31,83 +31,12 @@ class _MapContainerWidgetState extends State<MapContainerWidget> {
double screenWidth = constraints.maxWidth; double screenWidth = constraints.maxWidth;
double boxWidth = 0.86; double boxWidth = 0.86;
double boxHeight = 1.4; double boxHeight = 1.4;
<<<<<<< HEAD
return Column(
children: [
Container(
width: screenWidth * boxWidth,
height: screenWidth * boxHeight,
color: Colors.blue,
child: FlutterMap(
options: MapOptions(
center: LatLng(60.7666, 10.8471),
zoom: 9.0,
),
children: [
TileLayer(
urlTemplate: "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
subdomains: const ['a', 'b', 'c'],
),
MarkerLayer(
markers: widget.markerList.map((MarkerTemplate markerTemplate) {
return Marker(
width: markerTemplate.size,
height: markerTemplate.size,
point: markerTemplate.location,
builder: (ctx) => GestureDetector(
onTap: () {
setState(() {
selectedMarker = markerTemplate;
});
},
child: Image.asset(
'assets/icons/circle-red.png',
// Path to your custom icon asset
color: markerTemplate.color,
width: markerTemplate.size,
height: markerTemplate.size,
),
),
);
}).toList(),
),
/*PolygonLayer(
polygons: [
Polygon(
points: [
LatLng(60.7600, 10.8000),
LatLng(60.7600, 11.0000),
LatLng(60.7000, 11.0000),
LatLng(60.7000, 10.8000),
],
color: Colors.blue,
isFilled: true,
),
],
),*/
],
),
),
const SizedBox(height: contPadding), // Padding between containers
Container(
//width: screenWidth * boxWidth,
height: screenWidth * boxHeight*1.5, // NB: make dynamic
color: const Color(0xFF64B5F6),
child: Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.only(top: 20, left: 20), // Edge padding, text
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
=======
return Column( return Column(
children: [ children: [
const SizedBox(height: contPadding), const SizedBox(height: contPadding),
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
child: Stack( child: Stack(
>>>>>>> faa9a56f985acdab1c81feefa6cee6b055f14b19
children: [ children: [
SizedBox( SizedBox(
width: screenWidth * boxWidth, width: screenWidth * boxWidth,
...@@ -123,22 +52,22 @@ class _MapContainerWidgetState extends State<MapContainerWidget> { ...@@ -123,22 +52,22 @@ class _MapContainerWidgetState extends State<MapContainerWidget> {
subdomains: const ['a', 'b', 'c'], subdomains: const ['a', 'b', 'c'],
), ),
MarkerLayer( MarkerLayer(
markers: widget.markerList.map((MarkerTemplate markerTemplate) { markers: widget.markerList.map((Measurement Measurement) {
return Marker( return Marker(
width: markerTemplate.size, width: 50,
height: markerTemplate.size, height: 50,
point: markerTemplate.location, point: LatLng(Measurement.dataList[0].latitude, Measurement.dataList[0].longitude),
builder: (ctx) => GestureDetector( builder: (ctx) => GestureDetector(
onTap: () { onTap: () {
setState(() { setState(() {
selectedMarker = markerTemplate; selectedMarker = Measurement;
}); });
}, },
child: Image.asset( child: Image.asset(
'assets/icons/circle-red.png', 'assets/icons/circle-red.png',
color: markerTemplate.color, color: Colors.red,
width: markerTemplate.size, width: 50,
height: markerTemplate.size, height: 50,
), ),
), ),
); );
...@@ -209,11 +138,11 @@ class _MapContainerWidgetState extends State<MapContainerWidget> { ...@@ -209,11 +138,11 @@ class _MapContainerWidgetState extends State<MapContainerWidget> {
style: titleStyle, style: titleStyle,
), ),
Text( Text(
'Safety level: ${selectedMarker?.geoData.safetyLevel}', 'Time of measurement: ${selectedMarker?.timeMeasured}',
style: regTextStyle, style: regTextStyle,
), ),
Text( Text(
'Location: (${selectedMarker?.geoData.latitude},${selectedMarker?.geoData.longitude})', 'Location: (placeholder, placeholder)',
style: regTextStyle, style: regTextStyle,
), ),
const SizedBox(height: contPadding), const SizedBox(height: contPadding),
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
import FlutterMacOS import FlutterMacOS
import Foundation import Foundation
import path_provider_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
} }
No preview for this file type
import os import os
import sys import sys
from bson import json_util from bson import json_util
current_dir = os.path.dirname(__file__) current_dir = os.path.dirname(__file__)
parent_dir = os.path.abspath(os.path.join(current_dir, '..')) parent_dir = os.path.abspath(os.path.join(current_dir, '..'))
sys.path.append(parent_dir) sys.path.append(parent_dir)
...@@ -10,40 +11,60 @@ import json ...@@ -10,40 +11,60 @@ import json
# get_markers requests all marker data from mongoDB # get_markers requests all marker data from mongoDB
def get_all_markers(self, cursor): def get_all_markers(self, cursor):
try: try:
# Fetch all data # Fetch all data
cursor.execute(''' cursor.execute('''
SELECT m.MeasurementID, m.SensorID, m.TimeMeasured, m.Latitude, m.Longitude, SELECT m.MeasurementID, m.SensorID, m.TimeMeasured, d.Latitude, d.Longitude,
m.MeasuredThickness, m.Accuracy, s.SensorType, s.Active d.IceTop, d.IceBottom, d.CalculatedThickness, d.Accuracy, s.SensorType, s.Active
FROM Measurement m FROM Measurement m
INNER JOIN Sensor s ON m.SensorID = s.SensorID INNER JOIN Sensor s ON m.SensorID = s.SensorID
INNER JOIN Data d ON m.MeasurementID = d.MeasurementID
''') ''')
rows = cursor.fetchall() rows = cursor.fetchall()
data = [] measurement_data = {}
for row in rows: for row in rows:
measurement = { measurement_id = row[0]
'MeasurementID': row[0], data_object = {
'Latitude': row[3],
'Longitude': row[4],
'IceTop': row[5],
'IceBottom': row[6],
'CalculatedThickness': row[7],
'Accuracy': row[8]
}
# Append data with measurement ID x to measurement x object
if measurement_id in measurement_data:
measurement_data[measurement_id]['Data'].append(data_object)
else:
# Create a new measurement entry if measurement ID doesn't exist already
measurement_data[measurement_id] = {
'MeasurementID': measurement_id,
'TimeMeasured': row[1], 'TimeMeasured': row[1],
'Latitude': row[2],
'Longitude': row[3],
'MeasuredThickness': row[4],
'Accuracy': row[5],
'Sensor': { 'Sensor': {
'SensorID': row[6], 'SensorID': row[2],
'SensorType': row[7], 'SensorType': row[9],
'Active': bool(row[8]) 'Active': bool(row[10])
},
'Data': [data_object]
} }
}
data.append(measurement)
# Convert dictionary values to list of measurements
data = list(measurement_data.values())
if len(rows) == 0 or len(data) == 0: # Return 500 and empty list if no data is found
print(f"An error occurred while querying the database")
resp_code = 500
marker_json = '[]'
else:
resp_code = 200 resp_code = 200
# Convert the list of dictionaries to JSON # Convert list of dictionaries to JSON
marker_json = json.dumps(data, indent=4) marker_json = json.dumps(data, indent=4)
except Exception as e: except Exception as e:
print(f"An error occurred while querying MongoDB: {e}") print(f"An error occurred while querying the database: {e}")
resp_code = 500 resp_code = 500
marker_json = '[]' marker_json = '[]'
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment