Skip to content
Snippets Groups Projects
addevent.dart 11.1 KiB
Newer Older
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
Maximilian Betz's avatar
Maximilian Betz committed
import 'package:flutter/services.dart';
import 'package:flutter_datetime_picker/flutter_datetime_picker.dart';
import 'datamodel.dart';
Maximilian Betz's avatar
Maximilian Betz committed
import 'dart:async';
import 'package:geolocator/geolocator.dart';
Maximilian Betz's avatar
Maximilian Betz committed
class AddEvent extends StatefulWidget {
Maximilian Betz's avatar
Maximilian Betz committed
  const AddEvent({Key? key}) : super(key: key);

Maximilian Betz's avatar
Maximilian Betz committed
  @override
  State<AddEvent> createState() => _AddEventPageState();
}

class _AddEventPageState extends State<AddEvent>  {
  bool syncGNSSData = true;
  late LocationPermission permission;
  late Position position;
  late String long = "";
  late String lat = "";
  late String alt = "";
Maximilian Betz's avatar
Maximilian Betz committed
  late double accuracy = 0.0;
  late StreamSubscription<Position> positionStream;
  LocationSettings locationSettings = const LocationSettings(
    accuracy: LocationAccuracy.high,
    distanceFilter: 0,
  );

  getLocation() async {
    StreamSubscription<Position> positionStream = Geolocator.getPositionStream(
        locationSettings: locationSettings).listen((Position position) {
Maximilian Betz's avatar
Maximilian Betz committed
      debugPrint('Get Location: Lat:' + position.latitude.toString() +
          ' Long:' + position.longitude.toString() +
          ' Alt:' + position.altitude.toString());

      long = position.longitude.toString();
      lat = position.latitude.toString();
      alt = position.altitude.toString();
Maximilian Betz's avatar
Maximilian Betz committed
      accuracy = position.accuracy;
      if (syncGNSSData == true) {
        if(mounted){
          setState(() {
            //refresh UI on update
          });}
  startGNSS() async {
Maximilian Betz's avatar
Maximilian Betz committed
    debugPrint("Check Location Permission");
    bool serviceStatus = false;
    bool hasPermission = false;
    serviceStatus = await Geolocator.isLocationServiceEnabled();
    if(serviceStatus){
      permission = await Geolocator.checkPermission();

      if (permission == LocationPermission.denied) {
        permission = await Geolocator.requestPermission();
        if (permission == LocationPermission.denied) {
Maximilian Betz's avatar
Maximilian Betz committed
          debugPrint('Location permissions are denied');
        }else if(permission == LocationPermission.deniedForever){
Maximilian Betz's avatar
Maximilian Betz committed
          debugPrint('Location permissions are permanently denied');
        }else{
Maximilian Betz's avatar
Maximilian Betz committed
          hasPermission = true;
Maximilian Betz's avatar
Maximilian Betz committed
        hasPermission = true;
Maximilian Betz's avatar
Maximilian Betz committed
      if(hasPermission){
        debugPrint('Location permissions granted');
        if(mounted){
          setState(() {
            //refresh the UI
          });};

        getLocation();
      }
    }else{
Maximilian Betz's avatar
Maximilian Betz committed
      debugPrint("GPS Service is not enabled, turn on GPS location");
Maximilian Betz's avatar
Maximilian Betz committed
    if(mounted){
      setState(() {
        //refresh the UI
      });}
Maximilian Betz's avatar
Maximilian Betz committed

  @override
  void initState() {
    startGNSS();
Maximilian Betz's avatar
Maximilian Betz committed
    super.initState();
  }

  void _storeCurrentEvent() {
    final EventStoreInstance eventsStore = EventStoreInstance();
    eventsStore.currentEvent.status = "PENDING";
    eventsStore.events.add(
            eventsStore.currentEvent.id,
            eventsStore.currentEvent.urn,
            eventsStore.currentEvent.label,
            eventsStore.currentEvent.type,
            eventsStore.currentEvent.description,
            eventsStore.currentEvent.status,
            eventsStore.currentEvent.startDate,
            eventsStore.currentEvent.endDate,
            eventsStore.currentEvent.latitude,
            eventsStore.currentEvent.longitude,
            eventsStore.currentEvent.elevation
  //TODO: add field validators for freetext fields. Check allowed characters in sensor.awi.de

  @override
  Widget build(BuildContext context) {
    /* Get singletons to access relevant data here.*/
    final EventStoreInstance eventsStore = EventStoreInstance();
    final ConfigurationStoreInstance configuration = ConfigurationStoreInstance();
    String gnssStatusText = "";
    final formKey = GlobalKey<FormState>(); //key for form


    if (true == syncGNSSData){
Maximilian Betz's avatar
Maximilian Betz committed
      // Update current event coordinates from GNSS stream
      eventsStore.currentEvent.latitude = lat;
      eventsStore.currentEvent.longitude = long;
      eventsStore.currentEvent.elevation = alt;
      var date = DateTime.now().toUtc();
      eventsStore.currentEvent.startDate = '$date';
      eventsStore.currentEvent.endDate = '$date';

      if(accuracy == 0.0){
        gnssStatusText = "No-Fix";
      else{
        gnssStatusText = "Precision: "+ accuracy.toStringAsFixed(2) +"m";
      }
Maximilian Betz's avatar
Maximilian Betz committed
    }
    else{
Maximilian Betz's avatar
Maximilian Betz committed
      gnssStatusText = "GNSS Disabled"; // Just display existing event coordinates
    return Scaffold(
      appBar: AppBar(title: const Text("Add Event")),
      body:
      Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            TextFormField(
              initialValue: eventsStore.currentEvent.label,
              autovalidateMode: AutovalidateMode.onUserInteraction,
              decoration: const InputDecoration(
                  labelText: 'Label',
                  errorText: 'Only: a-z , A-Z , _ , 0-9 , ,(Comma) , ( , ) , + , - , . , :'
              onChanged: (value) {
                eventsStore.currentEvent.label = value;
              validator: (value){
                if(!RegExp(r'^[a-z A-Z . \- 0-9 , ( ) + - _ :]+$').hasMatch(value!)){
                  return "Only: a-z , A-Z , _ , 0-9 , ,(Comma) , ( , ) , + , - , . , :";
                }else{
                  eventsStore.currentEvent.label = value;
                  return '';  // Entered Text is valid
                }
              },

            ),
            DropdownButtonFormField(
                value: eventsStore.currentEvent.type,
                decoration: const InputDecoration(
                  labelText: 'Event Type',
                ),
                configuration.eventTypes.map((EventType event) {
Maximilian Betz's avatar
Maximilian Betz committed
                  return DropdownMenuItem(
                    value: event.name,
                    child: Text(event.name),
                  );
                }).toList(),
                onChanged: (value) {
                  eventsStore.currentEvent.type = value.toString();
                }
            ),
            DropdownButtonFormField(
                value: eventsStore.currentEvent.urn,
                decoration: const InputDecoration(
                  labelText: 'URN',
                ),
                configuration.devices.map((Device device) {
                  return DropdownMenuItem(
                    value: device.urn,
                    child: Text(device.urn),
                  );
                }).toList(),
                onChanged: (value) {
                  eventsStore.currentEvent.urn = value.toString();
                  eventsStore.currentEvent.id = configuration.getDeviceIdFromUrn(value.toString());
              initialValue: eventsStore.currentEvent.description,
              decoration: const InputDecoration(
                  labelText: 'Description'
              ),
              onChanged: (value) {
                eventsStore.currentEvent.description = value;

            Row(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  Flexible(child:
                  TextFormField(
                    controller: TextEditingController(text: eventsStore.currentEvent.startDate),
                    readOnly: true,
                    decoration: const InputDecoration(
                      labelText: 'Timestamp',
                      //helperText: '', //Adds some space below field
                      border: OutlineInputBorder(),
                    ),
                    onTap: () {
                      DatePicker.showDateTimePicker(context,
                          showTitleActions: true,
                          onConfirm: (date) {
                            //Only one field for start and end date.
                            eventsStore.currentEvent.startDate = '$date';
                            eventsStore.currentEvent.endDate = '$date';
                            debugPrint('Date set to : $date');
                            setState(() {
                            });
                          },
                          currentTime: DateTime.now().toUtc(),
                          locale: LocaleType.en);
                    },
                  ),
                  ),
                  ElevatedButton(
                    onPressed: () {
                      var date =  DateTime.now().toUtc();
                      eventsStore.currentEvent.startDate = '$date';
                      eventsStore.currentEvent.endDate = '$date';
                      debugPrint('Date set to : ' + eventsStore.currentEvent.endDate.toString());
                    child: Text('Now'),
                  ),
                ]
            TextFormField(
                readOnly: false,
                enabled: !syncGNSSData,
                controller: TextEditingController(text: eventsStore.currentEvent.latitude.toString()),
                decoration: const InputDecoration(
                  labelText: 'Latitude',
                  border: OutlineInputBorder(),
                ),
                onChanged: (value) {
                  eventsStore.currentEvent.latitude = value;
            TextFormField(
                readOnly: false,
                enabled: !syncGNSSData,
                controller: TextEditingController(text: eventsStore.currentEvent.longitude.toString()),
                decoration: const InputDecoration(
                  labelText: 'Longitude',
                  border: OutlineInputBorder(),

                ),
                onChanged: (value) {
                  eventsStore.currentEvent.longitude = value;
            TextFormField(
                readOnly: false,
                enabled: !syncGNSSData,
                controller: TextEditingController(text: eventsStore.currentEvent.elevation.toString()),
                decoration: const InputDecoration(
                  labelText: 'Elevation',
                  border: OutlineInputBorder(),
                ),
                onChanged: (value) {
                  eventsStore.currentEvent.elevation = value;
          ]),
      bottomNavigationBar: Row(
        mainAxisAlignment: MainAxisAlignment.end,
          Text(gnssStatusText),
          const SizedBox(width: 10),
          Switch(
            value: syncGNSSData,
            onChanged: (value) {
              syncGNSSData = value;
              debugPrint('Switched to:' + syncGNSSData.toString());

Maximilian Betz's avatar
Maximilian Betz committed
              setState(() {
                //refresh the UI
          const SizedBox(width: 50),
          FloatingActionButton(
            heroTag: null,
Maximilian Betz's avatar
Maximilian Betz committed
            onPressed: () {
              _storeCurrentEvent();
              HapticFeedback.vibrate();
            },
            tooltip: 'Add Event',
Maximilian Betz's avatar
Maximilian Betz committed
            child: const Icon(Icons.check),
          const SizedBox(width: 20),