Skip to content
Snippets Groups Projects
Select Git revision
  • 5f6768c7489cc531b99772cc12db73ee9c79106b
  • main default
  • clhp_map
  • Sentinenl_hub_integration
  • connect_data_to_map
  • NveWeatherbasedIntegration
  • lidar_test
  • app2
  • app-sql
  • server
  • app
11 results

main_layout.dart

Blame
  • main_layout.dart 13.71 KiB
    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 'info_layer.dart';
    import '../../consts.dart';
    import 'choropleth_map.dart';
    import '../data_classes.dart';
    import '../utils/export_data.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<SubDiv> subdivisions;
      final List<Measurement> measurements;
      final  Uint8List relation;
      final bool serverConnection;
    
      const MapContainerWidget({Key? key,
        required this.subdivisions,
        required this.measurements,
        required this.relation,
        required this.serverConnection,
      }) : super(key: key);
    
      @override
      _MapContainerWidgetState createState() => _MapContainerWidgetState();
    }
    
    class _MapContainerWidgetState extends State<MapContainerWidget> {
      // Button state trackers
      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
      bool infoLayer = false;       // Additional color information visibility
    
      // Initialise selected measurement to arbitrary value
      Measurement? selectedMeasurement = selectedMeasurements[0];
      final GlobalKey<ChoroplethMapState> _choroplethMapKey = GlobalKey();
    
      /// 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(
                            key: _choroplethMapKey,
                            relation: widget.relation,
                            measurements: widget.measurements,
                            subdivisions: widget.subdivisions,
                            onSelectionChanged: handleSelection,
                          ),
                        ),
                      ),
                      SizedBox(
                        width: screenWidth * boxWidth,
                        height: screenWidth * boxHeight,
                        child: Visibility(
                          visible: osmLayer,
                          child: OSM(markerList: widget.measurements),
                        ),
                      ),
                      SizedBox(
                        width: screenWidth * boxWidth,
                        height: screenWidth * boxHeight,
                        child: Visibility(
                          visible: infoLayer,
                          child: const InfoLayer(),
                        ),
                      ),
                      Positioned( // Satellite button
                        top: 10,
                        right: 10,
                        child: GestureDetector(
                          onTap: () {
                            setState(() {
                              satLayer = !satLayer; // Toggle satellite layer state on press
                              osmLayer = false;     // Turn OSM layer off if it was turned on
                            });
                          },
                          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
                              satLayer = false;     // Turn sat layer off if it was turned on
                            });
                          },
                          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( // Export button
                        top: 90,
                        right: 10,
                        child: GestureDetector(
                          onTap: () {
                            showModalBottomSheet(
                                context: context,
                                builder: (BuildContext context) {
                                  return SizedBox(
                                    height: 200,
                                    width: screenWidth,
                                    child: Center(
                                        child: Column(
                                          mainAxisAlignment: MainAxisAlignment.center,
                                          children: [
                                            Text(
                                                "Export ice data for $selectedLake",
                                                style: const TextStyle(fontSize: 20),
                                            ),
                                            const SizedBox(height: contPadding),
                                            ElevatedButton(
                                              style: ButtonStyle(
                                                backgroundColor: MaterialStateProperty.all<Color>(Colors.white24),
                                              ),
                                              child: const Text("Export JSON"),
                                              onPressed: () {
                                                // Close bottom sheet before displaying progress bar
                                                showProgressIndicator(context);
    
                                              },
                                            )
                                          ],
                                        ),
                                    ),
                                  );
                                },
                            );
                          },
                          child: Container(
                              padding: const EdgeInsets.all(8),
                              decoration: isSatTapped ? const BoxDecoration(
                                shape: BoxShape.circle,
                                color: Colors.blue,
                              ) : null,
                            child: const Icon(
                              Icons.share,
                              color: Colors.white54,
                            ),
                          ),
                        ),
                      ),
                      Positioned( // Color info layer button
                        top: 170,
                        right: 10,
                        child: GestureDetector(
                          onTap: () {
                            setState(() {
                              infoLayer = !infoLayer; // Toggle satellite layer state on press
                            });
                          },
                          child: Container(
                            padding: const EdgeInsets.all(8),
                            decoration: infoLayer ? const BoxDecoration( // Add decoration only when pressed
                              shape: BoxShape.circle,
                              color: Colors.grey,
                            ) : null,
                            child: const Icon(
                              Icons.info,
                              color: Colors.white54,
                            ),
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
                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), // Custom padding
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text(
                                'Ice stats',
                                style: titleStyle,
                              ),
                              const Divider(),
                              const SizedBox(height: 10),
                              Text(
                                'Tile ID: ${selectedSubDiv?.sub_div_id}',
                                style: regTextStyle,
                              ),
                              const SizedBox(height: 20),
                              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(
                                'Center coordinate: (${selectedSubDiv?.center.latitude}, ${selectedSubDiv?.center.longitude})',
                                style: regTextStyle,
                              ),
                              const SizedBox(height: contPadding/3),
                              Text(
                                'Data certainty: ${selectedSubDiv?.accuracy}/4',
                                style: subHeadingStyle,
                              ),
                            ],
                          ),
                        ),
                      ),
                    ),
                    const SizedBox(height: contPadding*2.5),
                    SizedBox(
                      width: screenWidth * boxWidth * 1.2,
                      child: const StatCharts(),
                    ),
                    const SizedBox(height: contPadding*4),
                  ],
                ),
              ],
            );
          },
        );
      }
    }