Newer
Older
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'satellite_layer.dart';
import 'stat_charts.dart';
import '../../consts.dart';
import 'choropleth_map.dart';
import '../data_classes.dart';
import 'quick_view_chart.dart';
/// MapContainerWidget is the main widget that contains the map with all
/// its layers, polygons and markers.
class MapContainerWidget extends StatefulWidget {
final List<Measurement> markerList;
const MapContainerWidget({Key? key,
required this.markerList,
required this.serverConnection,
@override
_MapContainerWidgetState createState() => _MapContainerWidgetState();
}
class _MapContainerWidgetState extends State<MapContainerWidget> {
Measurement? selectedTile; // Containing data for selected marker
bool isMinimized = true; // Quick view box state tacker
bool satLayer = false; // Satellite layer visibility tracker
bool isTapped = false; // Button tap state tracker
// 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(() {
// NB should be optimalised
for (Measurement measurement in widget.markerList) {
for (SubDiv subdivision in measurement.subDivs) {
if (subdivision.sub_div_id == indexString) {
selectedTile= widget.markerList[index];
break;
}
}
}
});
}
@override
Widget build(BuildContext context) {
// Initialise selectedMarker to first element in markerList
selectedTile ??= widget.markerList[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),
/*if (true) NB: add search bar
const SearchBar(),
const SizedBox(height: contPadding),*/
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(
SizedBox(
width: screenWidth * boxWidth,
height: screenWidth * boxHeight,
child: Stack(
children: [
OSM(markerList: widget.markerList), // OSM widget as the bottom layer
Positioned.fill(
child: Container(
color: Colors.grey.shade900.withOpacity(0.35), // Grey box with 50% opacity
// Additional content or widgets can be added here
),
),
],
),
),
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.markerList,
onSelectionChanged: handleSelection,),
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( // 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: isTapped ? 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}-${lastUpdate?.month}-${lastUpdate?.year}') : ''}',
style: GoogleFonts.dmSans(
fontSize: 14,
color: Colors.white60,
),
),
],
),
const SizedBox(height: contPadding), // Padding between containers
ClipRRect(
borderRadius: BorderRadius.circular(20),
width: screenWidth * boxWidth,
height: screenWidth * boxHeight * 1.5, // NB: make dynamic
child: Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.only(top: 20, left: 20), // Edge padding, text
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
style: titleStyle,
'Date: ${(selectedTile?.timeMeasured.day ?? '-')}/${(selectedTile?.timeMeasured.month ?? '-')}/${(selectedTile?.timeMeasured.year ?? '-')}',
'Time: ${selectedTile?.timeMeasured.hour}:00',
style: regTextStyle,
),
const SizedBox(height: contPadding),
'Measuring point: (${selectedTile?.measurementID}, ${selectedTile?.measurementID})',
const SizedBox(height: contPadding),
const StatCharts(),
],
),
),
),
],
);
},