Skip to content
Snippets Groups Projects
Commit 558a6746 authored by Hoa Ben The Nguyen's avatar Hoa Ben The Nguyen
Browse files

merge: solve merge

parents 40a58c2f 0e01a33c
No related branches found
No related tags found
No related merge requests found
Showing
with 317 additions and 161605 deletions
This diff is collapsed.
This diff is collapsed.
...@@ -8,20 +8,21 @@ const String serverURI = "https://127.0.0.1:$port/"; ...@@ -8,20 +8,21 @@ const String serverURI = "https://127.0.0.1:$port/";
const String mapEndpoint = "update_map"; const String mapEndpoint = "update_map";
const int fetchInterval = 60; // Fetch marker data every n minutes const int fetchInterval = 60; // Fetch marker data every n minutes
// Map center // Map variables
LatLng mapCenter = LatLng(60.7666, 10.8471); LatLng mapCenter = LatLng(60.7666, 10.8471);
DateTime ?lastUpdate; // Last time marker data was fetched from server
// Font variables // Font variables
const textColor = Colors.white; const textColor = Colors.white;
final appTitleStyle = GoogleFonts.dmSans( final appTitleStyle = GoogleFonts.dmSans(
fontSize: 35, fontSize: 35,
color: Colors.black, color: Colors.black,
fontWeight: FontWeight.bold, // Add this line to make the text bold fontWeight: FontWeight.bold,
); );
final titleStyle = GoogleFonts.dmSans( final titleStyle = GoogleFonts.dmSans(
fontSize: 35, fontSize: 35,
color: textColor, color: textColor,
fontWeight: FontWeight.bold, // Add this line to make the text bold fontWeight: FontWeight.bold,
); );
final regTextStyle = GoogleFonts.dmSans(fontSize: 19, color: textColor); final regTextStyle = GoogleFonts.dmSans(fontSize: 19, color: textColor);
final chartTextStyle = GoogleFonts.dmSans(fontSize: 14, color: textColor); final chartTextStyle = GoogleFonts.dmSans(fontSize: 14, color: textColor);
......
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'widgets/map_widget.dart'; import 'widgets/map_widget.dart';
import 'marker_handler/marker_data.dart'; import 'marker_handler/marker_data.dart';
import 'consts.dart'; import 'consts.dart';
import 'marker_handler/get_markers.dart'; import 'marker_handler/get_markers.dart';
import 'marker_handler/get_relation.dart'; import 'marker_handler/get_relation.dart';
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:io';
import 'dart:convert';
class DefaultPage extends StatefulWidget { class DefaultPage extends StatefulWidget {
const DefaultPage({super.key}); const DefaultPage({Key? key}) : super(key: key);
@override @override
_DefaultPageState createState() => _DefaultPageState(); _DefaultPageState createState() => _DefaultPageState();
...@@ -17,56 +20,36 @@ class DefaultPage extends StatefulWidget { ...@@ -17,56 +20,36 @@ class DefaultPage extends StatefulWidget {
class _DefaultPageState extends State<DefaultPage> { class _DefaultPageState extends State<DefaultPage> {
late Timer _timer; late Timer _timer;
bool showBar = false; bool showBar = false;
bool serverConnection = true;
List<Measurement> markerList = []; late Future<List<Measurement>> markerListFuture;
Uint8List relation = Uint8List(0); late Future<Uint8List> relationFuture;
// Call fetchMarkerTemplate and await its result before setting the state
Future<void> loadMarkerList() async {
try {
List<Measurement> fetchedMarkers = await fetchMarkerData();
Uint8List fetchedRelation = await fetchRelation();
setState(() { // Initialise markers and relations
markerList = fetchedMarkers;
relation = fetchedRelation;
});
} catch (e) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text("Error"),
content: Text(e.toString()),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text("OK"),
),
],
);
},
);
}
}
// State initializer
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// Load marker data from server markerListFuture = fetchMarkerData().then((fetchResult) {
loadMarkerList(); List<Measurement> measurements = fetchResult.measurements;
serverConnection = fetchResult.connected;
// Return the measurements
return measurements;
}).catchError((error) {
throw Exception("Failed to fetch measurements: $error");
});
//relationFuture = fetchRelation();
relationFuture = Future.value(Uint8List(0));
// Schedule fetchMarkerData to run periodically based on fetchInterval from consts // Schedule fetchMarkerData to run periodically based on fetchInterval from consts
const Duration interval = Duration(minutes: fetchInterval); const Duration interval = Duration(minutes: fetchInterval); // NB fetchInterval value to be determined
_timer = Timer.periodic(interval, (timer) { _timer = Timer.periodic(interval, (timer) {
fetchMarkerData(); fetchMarkerData();
}); });
} }
// Fetch timer // Fetch-interval timer
@override @override
void dispose() { void dispose() {
// Cancel timer on widget termination // Cancel timer on widget termination
...@@ -77,34 +60,58 @@ class _DefaultPageState extends State<DefaultPage> { ...@@ -77,34 +60,58 @@ class _DefaultPageState extends State<DefaultPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
home: Container( home: Scaffold(
decoration: const BoxDecoration( // Set background color appBar: AppBar(
gradient: LinearGradient( title: const Text('IceMap'),
begin: Alignment.topCenter, actions: [
end: Alignment.bottomCenter, IconButton(
colors: [darkBlue, darkestBlue], icon: const Icon(Icons.search),
), onPressed: () {
), setState(() {
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
title: const Text('IceMap'),
actions: [
IconButton(
icon: const Icon(Icons.search),
onPressed: () {
showBar = !showBar; showBar = !showBar;
}, });
), },
], ),
), ],
body: ListView( ),
children: [ // Add main widget body: FutureBuilder(
MapContainerWidget(markerList: markerList, relation: relation), future: Future.wait([markerListFuture, relationFuture]),
], builder: (BuildContext context, AsyncSnapshot<List<dynamic>> snapshot) {
), // Display loading screen until data is fetched
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: Icon(
Icons.severe_cold,
color: Colors.blue,
size: 100,
));
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else {
if (!serverConnection) {
print("Failed to connect to server");
}
// Display default page once all data is loaded from server
List<Measurement> markerList = snapshot.data![0] as List<Measurement>;
Uint8List relation = snapshot.data![1] as Uint8List;
return Container( // Return container with list view and background color
decoration: const BoxDecoration( // Set background color
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [darkBlue, darkestBlue],
),
),
child: ListView(
children: [
MapContainerWidget(markerList: markerList, relation: relation),
],
),
);
}
},
), ),
), ),
); );
} }
} }
\ No newline at end of file
...@@ -3,9 +3,19 @@ import 'dart:convert'; ...@@ -3,9 +3,19 @@ import 'dart:convert';
import 'dart:io'; import 'dart:io';
import '../consts.dart'; import '../consts.dart';
import 'marker_data.dart'; import 'marker_data.dart';
import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/material.dart';
class FetchResult {
final List<Measurement> measurements;
final bool connected;
FetchResult(this.measurements, this.connected);
}
// fetchMarkerTemplate requests all marker data from the server // fetchMarkerTemplate requests all marker data from the server
Future<List<Measurement>> fetchMarkerData() async { Future<FetchResult> fetchMarkerData() async {
try { try {
// Custom HTTP client // Custom HTTP client
HttpClient client = HttpClient() HttpClient client = HttpClient()
...@@ -26,18 +36,42 @@ Future<List<Measurement>> fetchMarkerData() async { ...@@ -26,18 +36,42 @@ Future<List<Measurement>> fetchMarkerData() async {
// Attempt to parse response to Measurement object only if the body // Attempt to parse response to Measurement object only if the body
// contains correctly formatted data // contains correctly formatted data
if (jsonData != null && jsonData is List) { if (jsonData != null && jsonData is List) {
print(jsonData.map((data) => Measurement.fromJson(data)).toList()); Directory appDocumentsDirectory = await getApplicationDocumentsDirectory();
return jsonData.map((data) => Measurement.fromJson(data)).toList(); String filePath = '${appDocumentsDirectory.path}/last_data.json';
} else {
throw Exception('Failed to parse marker data: Unexpected response format'); try { // Write most recent time of update to file
await File(filePath).writeAsString(responseBody, mode: FileMode.write);
print('Lake data written to file');
} catch (error) { print('Error in writing to file: $error');}
// Update local and persistent lastUpdate variable
lastUpdate = DateTime.now();
final prefs = await SharedPreferences.getInstance();
await prefs.setString('lastUpdate', '${DateTime.now()}');
return FetchResult(jsonData.map((data) => Measurement.fromJson(data)).toList(), true);
} }
} else {
throw Exception('Failed to parse marker data: Empty response body');
} }
} else {
throw Exception('Failed to fetch marker data: Status code ${response.statusCode}');
} }
return loadSavedData();
} catch (e) { } catch (e) {
throw Exception('Failed to fetch marker data: ${e.toString()}'); return loadSavedData();
}
}
Future<FetchResult> loadSavedData() async {
// Get latest saved data from file if the server does not respond
Directory appDocumentsDirectory = await getApplicationDocumentsDirectory();
String filePath = '${appDocumentsDirectory.path}/last_data.json';
// Read file contents
File file = File(filePath);
if (await file.exists()) {
String contents = await file.readAsString();
List<dynamic> jsonData = json.decode(contents); // Parse JSON string from file
List<Measurement> measurements = jsonData.map((data) => Measurement.fromJson(data)).toList();
return FetchResult(measurements, false);
} else {
throw Exception('File does not exist');
} }
} }
...@@ -4,7 +4,6 @@ import 'dart:io'; ...@@ -4,7 +4,6 @@ import 'dart:io';
import '../consts.dart'; import '../consts.dart';
import 'dart:typed_data'; import 'dart:typed_data';
/// Fetch relation data from server /// Fetch relation data from server
Future<Uint8List> fetchRelation() async { Future<Uint8List> fetchRelation() async {
try { try {
...@@ -17,11 +16,12 @@ Future<Uint8List> fetchRelation() async { ...@@ -17,11 +16,12 @@ Future<Uint8List> fetchRelation() async {
var request = await client.getUrl(Uri.parse('${serverURI}get_relation')); var request = await client.getUrl(Uri.parse('${serverURI}get_relation'));
var response = await request.close(); // Close response body at end of function var response = await request.close(); // Close response body at end of function
// Parse body to JSON if request is ok // Try to parse body to JSON if request is ok
if (response.statusCode == 200) { if (response.statusCode == 200) {
var responseBody = await response.transform(utf8.decoder).join(); var responseBody = await response.transform(utf8.decoder).join();
if (responseBody.isNotEmpty) { if (responseBody.isNotEmpty) {
// Return relation data from the response body
return Uint8List.fromList(utf8.encode(responseBody)); return Uint8List.fromList(utf8.encode(responseBody));
} else { } else {
throw Exception('Response body is empty'); throw Exception('Response body is empty');
......
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:app/pages/consts.dart'; import '../marker_handler/marker_data.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_maps/maps.dart'; import 'package:syncfusion_flutter_maps/maps.dart';
import '../consts.dart'; import 'dart:math';
import 'dart:typed_data';
/// A class containing thickness for each subdivision of the map. /// A class containing thickness for each subdivision of the map.
class IceThicknessModel { class IceThicknessModel {
IceThicknessModel(this.subDivID, this.thickness); IceThicknessModel(this.subDivID, this.thickness);
final int subDivID; final String subDivID;
final double thickness; final int thickness;
} }
/// A stateful widget which contains a choropleth map. /// A stateful widget which contains a choropleth map.
/// The map data is fetched from the server, and the map is rendered /// The map data is fetched from the server, and the map is rendered
/// using the Syncfusion Flutter Maps library. /// using the Syncfusion Flutter Maps library.
class ChoroplethMap extends StatefulWidget { class ChoroplethMap extends StatefulWidget {
const ChoroplethMap({Key? key, required this.relation}) : super(key: key); const ChoroplethMap({Key? key,
required this.relation,
required this.measurements
}) : super(key: key);
final Uint8List relation; final Uint8List relation;
final List<Measurement> measurements;
@override @override
_ChoroplethMapState createState() => _ChoroplethMapState(); _ChoroplethMapState createState() => _ChoroplethMapState();
...@@ -27,11 +30,18 @@ class ChoroplethMap extends StatefulWidget { ...@@ -27,11 +30,18 @@ class ChoroplethMap extends StatefulWidget {
class _ChoroplethMapState extends State<ChoroplethMap> { class _ChoroplethMapState extends State<ChoroplethMap> {
late MapShapeSource mapShapeSource; late MapShapeSource mapShapeSource;
late final MapZoomPanBehavior _zoomPanBehavior = MapZoomPanBehavior();
List<IceThicknessModel> iceThicknessList = <IceThicknessModel>[]; List<IceThicknessModel> iceThicknessList = <IceThicknessModel>[];
@override @override
void initState() { void initState() {
super.initState(); super.initState();
final Random random = Random();
for (int i = 0; i <= 60; i++) {
int randomNumber = random.nextInt(21); // 0 -> 20
iceThicknessList.add(IceThicknessModel(i.toString(), randomNumber));
}
} }
@override @override
...@@ -41,9 +51,41 @@ class _ChoroplethMapState extends State<ChoroplethMap> { ...@@ -41,9 +51,41 @@ class _ChoroplethMapState extends State<ChoroplethMap> {
MapShapeLayer( MapShapeLayer(
source: MapShapeSource.memory( source: MapShapeSource.memory(
widget.relation, widget.relation,
shapeDataField: 'name', shapeDataField: 'properties.SubDivID',
dataCount: iceThicknessList.length,
primaryValueMapper: (int index) => iceThicknessList[index].subDivID,
shapeColorValueMapper: (int index) => iceThicknessList[index].thickness,
shapeColorMappers: const [
MapColorMapper(
from: null, // Default color
color: Colors.grey,
text: 'No value',
),
MapColorMapper(
from: 0,
to: 3,
color: Color.fromRGBO(223,169,254, 1),
text: '0-3'),
MapColorMapper(
from: 4,
to: 8,
color: Color.fromRGBO(190,78,253, 1),
text: '4-8'),
MapColorMapper(
from: 9,
to: 15,
color: Color.fromRGBO(167,17,252, 1),
text: '9-15'),
MapColorMapper(
from: 16,
to: 20,
color: Color.fromRGBO(170,20,250, 1),
text: '16-20'),
],
), ),
color: Colors.orange, //color: Colors.lightBlueAccent,
zoomPanBehavior: _zoomPanBehavior,
strokeColor: Colors.orange,
), ),
], ],
); );
......
...@@ -7,6 +7,8 @@ import 'sat_layer.dart'; ...@@ -7,6 +7,8 @@ import 'sat_layer.dart';
import 'package:flutter_map/flutter_map.dart'; import 'package:flutter_map/flutter_map.dart';
import 'cloropleth_map.dart'; import 'cloropleth_map.dart';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:google_fonts/google_fonts.dart';
import 'package:shared_preferences/shared_preferences.dart';
/// MapContainerWidget is the main widget that contains the map with all /// MapContainerWidget is the main widget that contains the map with all
/// its layers, polygons and markers. /// its layers, polygons and markers.
...@@ -31,17 +33,33 @@ class _MapContainerWidgetState extends State<MapContainerWidget> { ...@@ -31,17 +33,33 @@ class _MapContainerWidgetState extends State<MapContainerWidget> {
bool isTapped = false; // Button tap state tracker bool isTapped = false; // Button tap state tracker
final MapController _mapController = MapController(); // Map controller to re-center map view final MapController _mapController = MapController(); // Map controller to re-center map view
// recenterMap moves the map back to its initial view // recenterMap moves the map back to its initial view
void recenterMap() { void recenterMap() {
_mapController.move(mapCenter, 9.0); _mapController.move(mapCenter, 9.0);
} }
// Initialise lastUpdate variable from persistent storage if server fetch fails
Future<void> checkAndSetLastUpdate() async {
if (lastUpdate == null) {
final prefs = await SharedPreferences.getInstance();
final updateString = prefs.getString('lastUpdate');
if (updateString != null && updateString.isNotEmpty) {
final updateData = DateTime.parse(updateString);
setState(() {
lastUpdate = updateData;
});
}
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// Initialise selectedMarker to first element in markerList // Initialise selectedMarker to first element in markerList
selectedMarker ??= widget.markerList[0]; selectedMarker ??= widget.markerList[0];
checkAndSetLastUpdate();
const double contPadding = 30; // Container padding space const double contPadding = 30; // Container padding space
return LayoutBuilder( return LayoutBuilder(
...@@ -110,7 +128,25 @@ class _MapContainerWidgetState extends State<MapContainerWidget> { ...@@ -110,7 +128,25 @@ class _MapContainerWidgetState extends State<MapContainerWidget> {
width: screenWidth * boxWidth, width: screenWidth * boxWidth,
height: screenWidth * boxHeight, height: screenWidth * boxHeight,
child: Container( child: Container(
color: const Color(0x883366ff) color: const Color(0x883366ff),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 5),
Text( // Display time of most recent server fetch
'Last updated at ${lastUpdate != null ?
(lastUpdate?.day == DateTime.now().day &&
lastUpdate?.month == DateTime.now().month &&
lastUpdate?.year == DateTime.now().year ?
'${lastUpdate?.hour}:${lastUpdate?.minute}' :
'${lastUpdate?.day}-${lastUpdate?.month}-${lastUpdate?.year}') : ''}',
style: GoogleFonts.dmSans(
fontSize: 13,
color: Colors.black,
),
),
],
),
), ),
), ),
SizedBox( // Lake map SizedBox( // Lake map
...@@ -118,7 +154,7 @@ class _MapContainerWidgetState extends State<MapContainerWidget> { ...@@ -118,7 +154,7 @@ class _MapContainerWidgetState extends State<MapContainerWidget> {
height: screenWidth * boxHeight, height: screenWidth * boxHeight,
child: Padding( child: Padding(
padding: const EdgeInsets.all(15.0), // Padding around map padding: const EdgeInsets.all(15.0), // Padding around map
child: ChoroplethMap(relation: widget.relation), child: ChoroplethMap(relation: widget.relation, measurements: widget.markerList,),
), ),
), ),
Positioned( // Quick view box layered over map Positioned( // Quick view box layered over map
......
...@@ -34,10 +34,10 @@ class StatCharts extends StatelessWidget { ...@@ -34,10 +34,10 @@ class StatCharts extends StatelessWidget {
], ],
), ),
), ),
const SizedBox(height: 20), // Add appropriate padding between charts const SizedBox(height: 20),
SizedBox( SizedBox(
width: MediaQuery.of(context).size.width * 0.8, // Adjust width as needed width: MediaQuery.of(context).size.width * 0.8,
height: 160, // Adjust height as needed height: 160,
child: BarChart( child: BarChart(
BarChartData( BarChartData(
alignment: BarChartAlignment.spaceAround, alignment: BarChartAlignment.spaceAround,
...@@ -77,19 +77,19 @@ class StatCharts extends StatelessWidget { ...@@ -77,19 +77,19 @@ class StatCharts extends StatelessWidget {
BarChartGroupData( BarChartGroupData(
x: 0, x: 0,
barRods: [ barRods: [
BarChartRodData(y: 15, width: 10), // Example width BarChartRodData(y: 15, width: 10),
], ],
), ),
BarChartGroupData( BarChartGroupData(
x: 1, x: 1,
barRods: [ barRods: [
BarChartRodData(y: 10, width: 10), // Example width BarChartRodData(y: 10, width: 10),
], ],
), ),
BarChartGroupData( BarChartGroupData(
x: 2, x: 2,
barRods: [ barRods: [
BarChartRodData(y: 18, width: 10), // Example width BarChartRodData(y: 18, width: 10),
], ],
), ),
], ],
......
...@@ -6,7 +6,9 @@ import FlutterMacOS ...@@ -6,7 +6,9 @@ import FlutterMacOS
import Foundation import Foundation
import path_provider_foundation import path_provider_foundation
import shared_preferences_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
} }
...@@ -73,6 +73,14 @@ packages: ...@@ -73,6 +73,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.0"
file:
dependency: transitive
description:
name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
fl_chart: fl_chart:
dependency: "direct main" dependency: "direct main"
description: description:
...@@ -107,6 +115,11 @@ packages: ...@@ -107,6 +115,11 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
google_fonts: google_fonts:
dependency: "direct main" dependency: "direct main"
description: description:
...@@ -252,7 +265,7 @@ packages: ...@@ -252,7 +265,7 @@ packages:
source: hosted source: hosted
version: "0.2.1" version: "0.2.1"
path_provider: path_provider:
dependency: transitive dependency: "direct main"
description: description:
name: path_provider name: path_provider
sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b
...@@ -347,6 +360,62 @@ packages: ...@@ -347,6 +360,62 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.0" version: "5.0.0"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02"
url: "https://pub.dev"
source: hosted
version: "2.2.2"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
url: "https://pub.dev"
source: hosted
version: "2.3.5"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
...@@ -456,6 +525,14 @@ packages: ...@@ -456,6 +525,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "13.0.0" version: "13.0.0"
web:
dependency: transitive
description:
name: web
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
url: "https://pub.dev"
source: hosted
version: "0.5.1"
win32: win32:
dependency: transitive dependency: transitive
description: description:
...@@ -481,5 +558,5 @@ packages: ...@@ -481,5 +558,5 @@ packages:
source: hosted source: hosted
version: "1.0.4" version: "1.0.4"
sdks: sdks:
dart: ">=3.2.0 <4.0.0" dart: ">=3.3.0 <4.0.0"
flutter: ">=3.10.0" flutter: ">=3.19.0"
...@@ -16,6 +16,8 @@ dependencies: ...@@ -16,6 +16,8 @@ dependencies:
fl_chart: ^0.20.0-nullsafety1 fl_chart: ^0.20.0-nullsafety1
google_fonts: any google_fonts: any
syncfusion_flutter_maps: ^20.4.41 syncfusion_flutter_maps: ^20.4.41
path_provider: ^2.0.8
shared_preferences: any
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
...@@ -25,6 +27,4 @@ dev_dependencies: ...@@ -25,6 +27,4 @@ dev_dependencies:
flutter: flutter:
uses-material-design: true uses-material-design: true
assets: assets:
- assets/icons/ - assets/
- assets/mjosa.geojson
- assets/australia.json
File deleted
-----BEGIN CERTIFICATE-----
MIIFCzCCAvOgAwIBAgIIJciHvv6Yi4gwDQYJKoZIhvcNAQELBQAwSTEhMB8GA1UE
AxMYNjViYjZkMjVjNWE2NzgxMWUxOWMyYjY3MQ4wDAYDVQQLEwVBdGxhczEUMBIG
A1UEChMLTW9uZ29EQiBJbmMwHhcNMjQwMjAxMDkyMDE0WhcNMjYwMjAxMTAyMDE0
WjAWMRQwEgYDVQQDDAtjZXJ0X2FjY2VzczCCAiIwDQYJKoZIhvcNAQEBBQADggIP
ADCCAgoCggIBAMXNw9D4fe6IWhmOw1emqk5RETZXSCuyh0+uQNyXkQ0OVdl8j1TY
zXqpuvvilz/axIkSba9dMTx/ejKECPmaIlZC6vTgmzdHgftXsm8iBP1audnV36MG
6jvqM7qe1/lQdsDbi94mSLd13/l5hgrENpUgCzp76krcC5wusXLl3OizsYpwrRw6
uwiZm9DxoSIW87ClWJbklP3XLJHfg2lIPjEcdSHSJkLEcUNzmggYXt4OfiSx8zlr
C6X93zgbPMQZqfO3k3B9hrFzuKDqlIvIm4y3GVuZ0Xj6ncDq262nB4+V+YTAWDRK
5CkKZVJlig4ePd5zTsB2hzJnLBWRlor3L756kcdm/2YtkEijQrewOd4RCOcz5Jx6
aZdYQMzUPgVJXh0gtNzY/+wq2WBCcypM22WW8/3678iJoIG4hIXsWVtJOubqovB+
jsbyGMp+5fk1Kqgo7AkiDT7ld/8O60FeR4i7Pa7tiikKKyhg1SnqCwueTzIv43x4
DciEXKKJRFFwbhTKL2Ty3UkFqYtqD9drXT0p7c9XUs5tzO/Jsx1D+KUq0UosP/Cv
fwp5W31pwjeJyEKHrrVIMj3G/+x5wfmIcsKxj+q00NSerx6WYB5ds7BiMZWDqBWT
Oaj/1w5IY7BDkEslYgkpwosw/CGIYrvLqKpWk0l1L5OgaSjouMLbTAiBAgMBAAGj
KjAoMA4GA1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDAjANBgkq
hkiG9w0BAQsFAAOCAgEAeoAdO4BMhhqrfka11JHTggyEkBR742LpV4epKWVLFnru
b6+mZrWVCjKaYmOep1u/3f3imtz6Y9L0zFUBVLsE1scqWNK10gZyChrGJuVlOXRM
NXpoLtOvQUxdJmFPmbnBtP3N3GwdTlq7v8kkyoV0z0KoFxHvPIujlCuHPkY4iQc/
lJYpyzNSmrC3Nyk8jS5QksYaR3A1Ol2puJiqwZBDfl+0ECSS8ovScK4ccYqyo4ze
NT5Uwc0Hr2oHbY4CRViZm+VllwanKeYhFAR3zoLIk5MIh4YlwerZqYRadoKhmRty
1bIEOjeRXoZusF8lIF0/BSaYEnel3xCH5umQWyRUlOkAOnwbqtfY6EaW7xwNFHsS
D34sPvxRJHh9jnCv1127kb3S5aXO+uvqebhdBrP8SOq9pwMgVGhM9y6RsDfz6g78
Xj8ICrS7Ls+Rah4IX2cPkHkEd7CXuQ7Gsr8jY3RSTBoC1/u98mNIFrkaTYBWqGL4
X7m9rFWeI4zLwYHPsKO9hwI9+HwaKiVkE4L5tu1Ur0evougxg0T+Eu4VdC1Z6qbg
JJgbUz6oLtUU9Y4Wp2EHQGTzBTA2+1s7PBMQp/49SxpS0N6JILWtSXOqRQ3BQS6p
Zj0k4adusbJ82cMdImcpjjhUlt58kZ2Ms6F5nUU8Tw+XVDxaId2fZ+GhGTgse4I=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
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
RfOGEADT0A6yOPYYFn8dEALhBSz7
-----END PRIVATE KEY-----
File added
# Sensor contains data related to a single sensor
class Sensor:
def __init__(self, ID: int, type: str, active: bool):
self.ID = ID
self.type = type
self.active = active
def to_dict(self):
return {
'ID': self.ID,
'type': self.type,
'active': self.active
}
# DateTime contains the date and time for a measurement
class DateAndTime:
def __init__(self, year: int, month: int, day: int, hour: int, minute: int):
self.year = year
self.month = month
self.day = day
self.hour = hour
self.minute = minute
def to_dict(self):
return {
'year': self.year,
'month': self.month,
'day': self.day,
'hour': self.hour,
'minute': self.minute
}
# Measurement contains geo-data related to a single measurement point at a given time. It includes an instance
# of the class Sensor.
class Measurement:
def __init__(self, longitude: float, latitude: float, datetime: DateAndTime, sensor: Sensor, precipitation: float,
thickness: float,
max_weight: float, safety_level: float, accuracy: float):
self.longitude = longitude
self.latitude = latitude
self.datetime = datetime
self.sensor = sensor
self.precipitation = precipitation
self.thickness = thickness
self.max_weight = max_weight
self.safety_level = safety_level
self.accuracy = accuracy
def to_dict(self):
return {
'longitude': self.longitude,
'latitude': self.latitude,
'datetime': self.datetime.to_dict(),
'sensor': self.sensor.to_dict(),
'precipitation': self.precipitation,
'thickness': self.thickness,
'max_weight': self.max_weight,
'safety_level': self.safety_level,
'accuracy': self.accuracy
}
# MarkerTemplate is a template for map marker data. It includes an instance of the
# DataPoint type.
class MarkerTemplate:
def __init__(self, geoData: Measurement, size: float, color: str):
self.geoData = geoData
self.longitude = geoData.longitude
self.latitude = geoData.latitude
self.size = size
self.color = color
def to_dict(self):
return {
'geo_data': self.geoData.to_dict(),
'latitude': self.latitude,
'longitude': self.longitude,
'size': self.size,
'color': self.color,
}
File deleted
The following query
[out:json];
(
way["natural"="water"]["name"="lakeName"];
relation["natural"="water"]["name"="lakeName"];
);
/*added by auto repair*/
(._;>;);
/*end of auto repair*/
out body;
...@@ -2,9 +2,9 @@ from flask import Flask ...@@ -2,9 +2,9 @@ from flask import Flask
from http.server import HTTPServer, BaseHTTPRequestHandler from http.server import HTTPServer, BaseHTTPRequestHandler
from consts import SSL_CERT_PATH, SSL_KEY_PATH, HOST, PORT from consts import SSL_CERT_PATH, SSL_KEY_PATH, HOST, PORT
from map.get_markers import get_all_markers from map.get_markers import get_all_markers
from map.input_new_data import input_new_Lidar_data from map.get_relation import get_relation
#from map.get_relation import get_relation
from APIs.get_weather import get_weather from APIs.get_weather import get_weather
from map.input_new_data import input_new_Lidar_data
import ssl import ssl
import keyboard import keyboard
import sqlite3 import sqlite3
...@@ -43,8 +43,8 @@ class IceHTTP(BaseHTTPRequestHandler): ...@@ -43,8 +43,8 @@ class IceHTTP(BaseHTTPRequestHandler):
elif self.path == '/get_valid_markers': # NB: should be POST? elif self.path == '/get_valid_markers': # NB: should be POST?
get_all_markers(self, self.cursor, True, 'Mjosa') # Get only valid markers get_all_markers(self, self.cursor, True, 'Mjosa') # Get only valid markers
# NB: temporary hardcoded waterBodyName # NB: temporary hardcoded waterBodyName
#elif self.path == '/get_relation': elif self.path == '/get_relation':
# get_relation(self, 'Mjosa') # NB temp hardcoded value get_relation(self, 'Mjosa') # NB temp hardcoded value
def do_POST(self): def do_POST(self):
if self.path == '/get_weather_data': if self.path == '/get_weather_data':
...@@ -53,17 +53,6 @@ class IceHTTP(BaseHTTPRequestHandler): ...@@ -53,17 +53,6 @@ class IceHTTP(BaseHTTPRequestHandler):
elif self.path == '/new_lidar_data': elif self.path == '/new_lidar_data':
input_new_Lidar_data(self,self.cursor, 1, 'Mjosa') # hardcoded body of water must change later input_new_Lidar_data(self,self.cursor, 1, 'Mjosa') # hardcoded body of water must change later
# Terminate server on key press q
def on_key_press(server, event, cursor, conn):
if event.name == 'q':
print('Terminating server...')
server.server_close()
cursor.close()
conn.close()
keyboard.unhook_all()
quit()
# Start a server on port 8443 using self defined HTTP class # Start a server on port 8443 using self defined HTTP class
if __name__ == "__main__": if __name__ == "__main__":
try: try:
...@@ -81,11 +70,6 @@ if __name__ == "__main__": ...@@ -81,11 +70,6 @@ if __name__ == "__main__":
print("Server running on port ", PORT) print("Server running on port ", PORT)
# Register key press event handler
keyboard.on_press(lambda event: on_key_press(server, event, cursor, conn))
print("Server running on port ", PORT)
# Run server indefinitely # Run server indefinitely
server.serve_forever() server.serve_forever()
......
No preview for this file type
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment