Skip to content
Snippets Groups Projects
main_layout.dart 11.7 KiB
Newer Older
import 'dart:typed_data';
import 'package:flutter_map/flutter_map.dart';
import 'package:fuzzy/fuzzy.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'osm_layer.dart';
import 'search_bar.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';

/// MapContainerWidget is the main widget that contains the map with all
/// its layers, polygons and markers.
class MapContainerWidget extends StatefulWidget {
  final List<Measurement> markerList;
  final  Uint8List relation;
  final bool serverConnection;
  final bool showSearchBar;
  const MapContainerWidget({Key? key,
    required this.markerList,
    required this.relation,
    required this.serverConnection,
    required this.showSearchBar
  }) : super(key: key);

  @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 OSMlayer = false;

  bool isSatTapped = false;        // Button tap state tracker, satellite
  bool isMapTapped = false;        // Button tap state tracker, OSmap
  // 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();
      // 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;
        return Column(
          children: [
            const SizedBox(height: contPadding),
            if (widget.showSearchBar) // NB temp always true
              _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(
Sara Savanovic Djordjevic's avatar
Sara Savanovic Djordjevic committed
                      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.markerList,
                        onSelectionChanged: handleSelection,),
                  SizedBox(
                    width: screenWidth * boxWidth,
                    height: screenWidth * boxHeight,
                    child: Visibility(
                      visible: OSMlayer,
                      child: OSM(markerList: widget.markerList),
                  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,
Sara Savanovic Djordjevic's avatar
Sara Savanovic Djordjevic committed
                          color: Colors.grey,
Sara Savanovic Djordjevic's avatar
Sara Savanovic Djordjevic committed
                        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)),
                        ),
                      ),
                    ),
                  ),
Sara Savanovic Djordjevic's avatar
Sara Savanovic Djordjevic committed
            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: [
                        const Divider(),
Sara Savanovic Djordjevic's avatar
Sara Savanovic Djordjevic committed
                        const Padding(padding: EdgeInsets.all(10)),
Sara Savanovic Djordjevic's avatar
Sara Savanovic Djordjevic committed
                          'Measured at ',
                          style: subHeadingStyle,
Sara Savanovic Djordjevic's avatar
Sara Savanovic Djordjevic committed
                          '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 SizedBox(height: 15),
}


class _SearchBar extends StatelessWidget {
  final width = 350.0; // NB pass value to class
  final List<String> testSearchNames = [
    "Mjøsa",
    "Bogstadsvannet",
    "Einavatnet",
    "Femsjøen",
    "Femunden",
    "Fjellsjøen",
    "Gjende",
    "Gjersjøen"
  ];
  // Searching function for lake names using Fuzzy library
  List<String> searchLakeNames(String query) {
    final options = FuzzyOptions(threshold: 0.3, findAllMatches: true);
    final matcher = Fuzzy(testSearchNames, options: options);
    final results = matcher.search(query);

    // Extracting lake names from the results and casting them to strings
    return results.map((result) => result.item as String).toList();
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 16.0),
      child: SizedBox(
        height: 35, // Adjust the height here
        width: width,
        child: TextField(
          decoration: InputDecoration(
            contentPadding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
            hintText: 'Search...',
            filled: true,
            fillColor: Colors.white,
            border: OutlineInputBorder(
              borderRadius: BorderRadius.circular(15.0),
            ),
          ),
          onChanged: (value) {
            searchLakeNames(value);
          },
        ),
      ),
    );
  }