Skip to content
Snippets Groups Projects
viewevents.dart 10.3 KiB
Newer Older
import 'package:flutter/material.dart';
import 'datamodel.dart';
import 'sensorconnector.dart';
Maximilian Betz's avatar
Maximilian Betz committed
import 'databaseconnector.dart';
Maximilian Betz's avatar
Maximilian Betz committed
class ViewEvents extends StatefulWidget {
  const ViewEvents({Key? key}) : super(key: key);
Maximilian Betz's avatar
Maximilian Betz committed
  @override
  _ViewEvents createState() => _ViewEvents();
}
Maximilian Betz's avatar
Maximilian Betz committed
class _ViewEvents extends State<ViewEvents> {
Maximilian Betz's avatar
Maximilian Betz committed
  // Get singleton to access locally stored events:
  final EventStoreInstance _events = EventStoreInstance();
  String _status = '';
  TextStyle _statusStyle = const TextStyle(color: Colors.black);
  String _syncButtonText = 'Start Sync';
  bool _cancelSync = false;  //Flag to cancel sync process
  bool _currentlySyncing = false; // State flag to indicate if sync is ongoing
Maximilian Betz's avatar
Maximilian Betz committed
  var database = DatabaseInstance();
  List<Event> _localEvents = [];
Maximilian Betz's avatar
Maximilian Betz committed
  Future<void> fetchEventsFromDb() async{
    final EventStoreInstance event = EventStoreInstance();
    int pendingEvents = 0;

    if (event.showAllEvents == false) {
      _appBarText = 'Pending Events';
      //Get only pending events
      _localEvents = await database.getPendingEvents();
      pendingEvents = _localEvents.length;

    }else {
      _appBarText = 'All Events';
      _localEvents = await database.getEvents();
      pendingEvents = await database.getPendingEventCnt();
    }
    _status = pendingEvents.toString() + ' event(s) pending';
    _statusStyle = const TextStyle(color: Colors.black);
    setState(() {}); //Got events from database, so update UI
Maximilian Betz's avatar
Maximilian Betz committed

  @override
  void initState() {
    super.initState();
Maximilian Betz's avatar
Maximilian Betz committed
    fetchEventsFromDb();
  @override
  void dispose() async {

    /*Async update current configuration to shared preferences*/
    final EventStoreInstance event = EventStoreInstance();
    event.storeToSharedPrefs();
    super.dispose();
  Future<void> syncEvents() async {
    _cancelSync = false;
Maximilian Betz's avatar
Maximilian Betz committed
    final ConfigurationStoreInstance configuration = ConfigurationStoreInstance();
    SensorConnector connection = SensorConnector();
Maximilian Betz's avatar
Maximilian Betz committed

    List<Event> events = await database.getPendingEvents();
    int syncCounter = events.length;
Maximilian Betz's avatar
Maximilian Betz committed
    debugPrint('Pending Events');
    for (var event in events){
      debugPrint(event.toString());
    }

    if(syncCounter > 0) {
      try {
        String? token = await connection.getAuthToken(
            configuration.loginInformation.mail,
            configuration.loginInformation.password);
        var index = 0;
        for (var event in events) {
          if(_cancelSync == true){
            _currentlySyncing = false;
            _syncButtonText = 'Start Sync';
            debugPrint('Sync process canceled');
            return;
          }
          _currentlySyncing = true;
          _syncButtonText = 'Syncing ...';
          if(mounted) {
            setState(() {});
          }
          debugPrint('Idx: ' + index.toString() + ' ' +
              event.toSensorJson().toString());
          index++;
          if (await connection.putEvent(event, token) == true) {
            syncCounter--;
            debugPrint('put success, now pending: ' + syncCounter.toString());
            event.status = 'EXPORTED'; //Update event to export only once
            database.updateEvent(event); //Update Event as exported in SQL Database
            debugPrint('updated database');

            ////Update view list TODO: this is bad for the sync performance!
            await fetchEventsFromDb();
            if(mounted) {
              setState(() {});
            }

          } else {
            throw Exception('Sync for ' + event.urn + 'failed');
Maximilian Betz's avatar
Maximilian Betz committed
        }
        _status = 'export success';
        _statusStyle = const TextStyle(color: Colors.green);
      } catch (e) {
Maximilian Betz's avatar
Maximilian Betz committed
        String errorText = e.toString();
        errorText = errorText.substring(10, errorText.length);  //Remove 'Exception' from string.
        _status = errorText;
        _statusStyle = const TextStyle(color: Colors.red);
Maximilian Betz's avatar
Maximilian Betz committed
      }
      debugPrint('No PENDING event(s)');
Maximilian Betz's avatar
Maximilian Betz committed
    }
    _currentlySyncing = false;
    _syncButtonText = 'Start Sync';
    if(mounted) {
      setState(() {});
    }
Maximilian Betz's avatar
Maximilian Betz committed
  }
Maximilian Betz's avatar
Maximilian Betz committed

  @override
  Widget build(BuildContext context) {
    final EventStoreInstance event = EventStoreInstance();
    return Scaffold(
      appBar: AppBar(
        title: const Text("View & Sync"),
        actions: <Widget>[
          Text(_appBarText, style: const TextStyle(fontStyle: FontStyle.italic),),
          Switch(  //Enable showing all or only pending events. Default is to show only pending events
              value: event.showAllEvents,
              onChanged: (value) {
                event.showAllEvents = value;
                fetchEventsFromDb();
                setState(() {});
              }),
        ],
Maximilian Betz's avatar
Maximilian Betz committed
      body: Container(
        margin: const EdgeInsets.symmetric(horizontal: 5.0),
        child:
        SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: SingleChildScrollView(
            scrollDirection: Axis.vertical,
            child: DataTable(
Maximilian Betz's avatar
Maximilian Betz committed

              columns: const <DataColumn>[
                DataColumn(
                  label: Text(
                    style: TextStyle(fontStyle: FontStyle.italic),
                  ),
                DataColumn(
                  label: Text(
                    'Label',
                    style: TextStyle(fontStyle: FontStyle.italic),
                  ),
                DataColumn(
                  label: Text(
                    'Type',
                    style: TextStyle(fontStyle: FontStyle.italic),
                  ),
                DataColumn(
                  label: Text(
                    'Description',
                    style: TextStyle(fontStyle: FontStyle.italic),
                  ),
                DataColumn(
                  label: Text(
                    'StartDate',
                    style: TextStyle(fontStyle: FontStyle.italic),
                  ),
                DataColumn(
                  label: Text(
                    'EndDate',
                    style: TextStyle(fontStyle: FontStyle.italic),
                  ),
                DataColumn(
                  label: Text(
                    'Latitude',
                    style: TextStyle(fontStyle: FontStyle.italic),
                  ),
                DataColumn(
                  label: Text(
                    'Longitude',
                    style: TextStyle(fontStyle: FontStyle.italic),
                  ),
                DataColumn(
                  label: Text(
                    'Elevation',
                    style: TextStyle(fontStyle: FontStyle.italic),
                  ),
                DataColumn(
                  label: Text(
                    'Status',
                    style: TextStyle(fontStyle: FontStyle.italic),
                  ),
                DataColumn(
                  label: Text(
                    'Data',
                    style: TextStyle(fontStyle: FontStyle.italic),
                  ),
                ),
              ],
              rows: <DataRow>[
                //for (var event in _localEvents)
                for (var i = 0; i < _localEvents.length; i++)
                  DataRow(
                    selected: i == _selectedRow,
                    onLongPress: () {
                      if(_currentlySyncing == true){
                        _cancelSync = true;
                        return; //Cancel syncing before editing
                      }

                      debugPrint("Selected Row: " + i.toString());
                      var eventCopy = Event.fromEvent(_localEvents[i]);
                      if(eventCopy.status == 'PENDING'){
                        Navigator.pushNamed(context, '/fifth', arguments: {'event': eventCopy} ).then((_) => setState(() {fetchEventsFromDb();}));
                      }else
                      {
                        debugPrint('Can not edit already exported events.');
                        //TODO: display popup or grey out"Exported Events are read only, Edit via Sensor.awi.de" when trying to edit.
                      }
                    cells: <DataCell>[
                      //DataCell(Text(_localEvents[i].urnId.toString())),
                      DataCell(Text('('+_localEvents[i].urnId.toString()+')  ' + _localEvents[i].urn)),
                      DataCell(
                      DataCell(Text(_localEvents[i].type)),
                      DataCell(Text(_localEvents[i].description)),

                      DataCell(Text(_localEvents[i].startDate.substring(0, 19) + 'Z')),
                      DataCell(Text(_localEvents[i].endDate.substring(0, 19) + 'Z')),
                      DataCell(Text(_localEvents[i].latitude)),
                      DataCell(Text(_localEvents[i].longitude)),
                      DataCell(Text(_localEvents[i].elevation == '' ? '' : double.parse(_localEvents[i].elevation).toStringAsFixed(2))),
                      DataCell(Text(_localEvents[i].status)),
                      DataCell(Text(_localEvents[i].data)),
      bottomNavigationBar: Container(
        margin: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 5.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            const SizedBox(width: 1),
            Text(_status, style: _statusStyle),
            FloatingActionButton.extended(
              heroTag: null,
              tooltip: 'Upload Events',
              icon: null,
              label: Text(_syncButtonText),
              onPressed: () {
                if(_currentlySyncing == false){
                  _currentlySyncing = true;
                  syncEvents();
                }else{
                  debugPrint('Sync already running, canceling sync');
                  _cancelSync = true;