Newer
Older
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'stat_charts.dart';
import '../../consts.dart';
import 'choropleth_map.dart';
import '../data_classes.dart';
import 'satellite_layer.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;
const MapContainerWidget({Key? key,
required this.measurements,
required this.serverConnection,
@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) {
setState(() {
for (Measurement measurement in widget.measurements) {
for (SubDiv subdivision in measurement.subDivs) {
if (subdivision.sub_div_id == indexString) {
selectedSubDiv = subdivision;
selectedMeasurement = measurement;
});
}
@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
SizedBox( // Colored box behind map
width: screenWidth * boxWidth,
height: screenWidth * boxHeight,
child: Container(
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,
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
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),
],
);
},