import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'osm_layer.dart'; import 'stat_charts.dart'; import '../../consts.dart'; import 'choropleth_map.dart'; import '../data_classes.dart'; import 'satellite_layer.dart'; import 'quick_view_chart.dart'; import '../utils/format_month.dart'; /// MapContainerWidget is the main widget that contains the map with all /// its layers, polygons and markers. class MapContainerWidget extends StatefulWidget { final List<Measurement> measurements; final Uint8List relation; final bool serverConnection; const MapContainerWidget({Key? key, required this.measurements, required this.relation, required this.serverConnection, }) : super(key: key); @override _MapContainerWidgetState createState() => _MapContainerWidgetState(); } class _MapContainerWidgetState extends State<MapContainerWidget> { bool isMinimized = true; // Quick view box state tacker bool satLayer = false; // Satellite layer visibility state bool osmLayer = false; // OSM layer visibility state bool isSatTapped = false; // Satellite button tap state tracker bool isMapTapped = false; // OSM button tap state tracker Measurement? selectedMeasurement = selectedMarkerList[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; }); } } } // Tile selection handler void handleSelection(int index) { String indexString = index.toString(); setState(() { for (Measurement measurement in widget.measurements) { for (SubDiv subdivision in measurement.subDivs) { if (subdivision.sub_div_id == indexString) { selectedSubDiv = subdivision; selectedMeasurement = measurement; break; } } } }); } @override Widget build(BuildContext context) { // Initialise selectedMarker to first element in markerList selectedSubDiv ??= widget.measurements[0].subDivs[0]; checkAndSetLastUpdate(); const double contPadding = 30; // Container padding space return LayoutBuilder( builder: (context, constraints) { double screenWidth = constraints.maxWidth; double boxWidth = 0.86; double boxHeight = 1.4; return Column( children: [ const SizedBox(height: contPadding*1.5), ClipRRect( borderRadius: BorderRadius.circular(20), child: Stack( // Stack of quick view, map layer, satellite layer, and buttons children: [ SizedBox( // Colored box behind map width: screenWidth * boxWidth, height: screenWidth * boxHeight, child: Container( color: Colors.white12, ), ), SizedBox( // Color coded lake polygon width: screenWidth * boxWidth, height: screenWidth * boxHeight, child: Padding( padding: const EdgeInsets.all(15.0), // Padding around map child: ChoroplethMap( relation: widget.relation, measurements: widget.measurements, onSelectionChanged: handleSelection,), ), ), SizedBox( width: screenWidth * boxWidth, height: screenWidth * boxHeight, child: Visibility( visible: osmLayer, child: OSM(markerList: widget.measurements), ), ), Positioned( // Satellite button top: 10, right: 10, child: GestureDetector( onTap: () { setState(() { satLayer = !satLayer; // Toggle satellite layer state on press }); }, child: Container( padding: const EdgeInsets.all(8), decoration: satLayer ? const BoxDecoration( // Add decoration only when pressed shape: BoxShape.circle, color: Colors.grey, ) : null, child: const Icon( Icons.satellite_alt_outlined, color: Colors.white54, ), ), ), ), Positioned( // OSmap button top: 50, right: 10, child: GestureDetector( onTap: () { setState(() { osmLayer = !osmLayer; // Toggle satellite layer state on press }); }, child: Container( padding: const EdgeInsets.all(8), decoration: osmLayer ? const BoxDecoration( // Add decoration only when pressed shape: BoxShape.circle, color: Colors.grey, ) : null, child: const Icon( Icons.map, color: Colors.white54, ), ), ), ), Positioned( // No wifi icon top: 80, right: 10, child: GestureDetector( onTapDown: (_) { setState(() { // Add functionality }); }, onTapUp: (_) { setState(() { // Add functionality }); }, onTapCancel: () { setState(() { // Add functionality }); }, child: Visibility( // Show icon only when no server connection visible: !widget.serverConnection, child: Container( padding: const EdgeInsets.all(8), decoration: isSatTapped ? const BoxDecoration( shape: BoxShape.circle, color: Colors.blue, ) : null, child: const Icon(Icons.perm_scan_wifi, color: Color(0xFF5B0000)), ), ), ), ), ], ), ), 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}.${formatMonth(lastUpdate!.month)} ${lastUpdate?.year}') : ''}', style: GoogleFonts.dmSans( fontSize: 14, color: Colors.white60, ), ), ], ), const SizedBox(height: contPadding), // Padding between containers Column( // Ice stats container crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( width: screenWidth * boxWidth, child: Align( alignment: Alignment.topLeft, child: Padding( padding: const EdgeInsets.only(top: 20, left: 30), // Updated padding child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Ice stats', style: titleStyle, ), const Divider(), const SizedBox(height: 10), // Reduced padding Text( 'Measured at ', style: subHeadingStyle, ), Text( 'Date: ${(selectedMeasurement?.timeMeasured.day ?? '-')}/${(selectedMeasurement?.timeMeasured.month ?? '-')}/${(selectedMeasurement?.timeMeasured.year ?? '-')}', style: regTextStyle, ), Text( 'Time: ${selectedMeasurement?.timeMeasured.hour}:00', style: regTextStyle, ), const SizedBox(height: contPadding), Text( 'Measuring point: (${selectedMeasurement?.measurementID}, ${selectedMeasurement?.measurementID})', style: regTextStyle, ), ], ), ), ), ), const SizedBox(height: contPadding*2.5), SizedBox( width: screenWidth * boxWidth * 1.2, child: const StatCharts(), ), const SizedBox(height: contPadding*4), ], ), ], ); }, ); } }