Newer
Older
import 'package:flutter/material.dart';
import 'datamodel.dart';
import 'sensorconnector.dart';
import 'databaseconnector.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
class Configuration extends StatefulWidget {
@override
State<Configuration> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<Configuration> {
late Future<Collection> futureCollection;
late Future<List<Collection>> futureCollections;
late Future<List<EventType>> futureEventTypes;
late Future<List<Device>> futureDevices;
late Future<String> futureAuthToken;
var database = DatabaseInstance();
SensorConnector connector = SensorConnector();
final ConfigurationStoreInstance configuration = ConfigurationStoreInstance();
TextStyle _statusStyle = const TextStyle(color: Colors.black);

Maximilian Betz
committed
Future<void> dumpToFile(BuildContext context) async{
var date = DateTime.now().toUtc();
var isoDate = date.toIso8601String();
String filename =
date.year.toString().padLeft(4, '0') +
date.month.toString().padLeft(2, '0') +
date.day.toString().padLeft(2, '0') +
date.hour.toString().padLeft(2, '0') +
date.minute.toString().padLeft(2, '0') +
date.second.toString().padLeft(2, '0') +
'_events.json';
String eventsJson = await database.eventDump();
final Directory? directory = await getExternalStorageDirectory();
if(directory != null) {
String filepath = join(directory.path, filename);
final File file = File(filepath);
await file.writeAsString(eventsJson);
debugPrint('Stored file at: ' + filepath);
_status = 'Event database dump created: ' + filepath;
_statusStyle = const TextStyle(color: Colors.green);
setState(() {});

Maximilian Betz
committed
_showResultPopup(context, _status);

Maximilian Betz
committed
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
void _showResultPopup(BuildContext context, String text) async {
// Declaring and Initializing OverlayState
// and OverlayEntry objects
OverlayState? overlayState = Overlay.of(context);
OverlayEntry overlayEntry;
overlayEntry = OverlayEntry(builder: (context) {
// You can return any widget you like
// here to be displayed on the Overlay
return Stack(
alignment: Alignment.center,
children: [
Positioned(
// Position at 10% of height from bottom
bottom: MediaQuery.of(context).size.height * 0.1,
child: Material(
borderRadius: BorderRadius.circular(8.0),
color: Colors.blue,
child: Container(
padding: const EdgeInsets.all(5.0), // Space between Text and Bubble
width: MediaQuery.of(context).size.width * 0.95,
child: TextFormField(
minLines: 1,
maxLines: 5,
readOnly: true,
autofocus: false,
enabled: false,
//style: _statusStyle,
controller: TextEditingController(
text: _status,
),
),
),
),
),
],
);
});
// Inserting the OverlayEntry into the Overlay
overlayState?.insert(overlayEntry);
// Awaiting for 5 seconds
await Future.delayed(const Duration(seconds: 5));
// Removing the OverlayEntry from the Overlay
overlayEntry.remove();
}
Future<void> updateConfiguration() async {
final EventStoreInstance event = EventStoreInstance();
String token = '';
try{
token = await connector.getAuthToken(configuration.loginInformation.mail, configuration.loginInformation.password);
configuration.devices = await connector.fetchCollectionDevices(configuration.currentCollection.id); //await futureDevices; //already fetched just use the data.
configuration.eventTypes = await connector.fetchEventTypes();
if (configuration.devices.isEmpty){
throw Exception('Collection with 0 devices.');
}
event.currentEvent.id = 0;
event.currentEvent.urnId = configuration.devices[0].id; //TODO: fix if devices are an empty list.
event.currentEvent.urn = configuration.devices[0].urn;
event.currentEvent.description = '';
event.currentEvent.label = '';
event.currentEvent.type = configuration.eventTypes[0].name;
var date = DateTime.now().toUtc();
var isoDate = date.toIso8601String();
event.currentEvent.startDate = isoDate;
event.currentEvent.endDate = isoDate;
configuration.initialized = true;
HapticFeedback.vibrate();
//TODO: display success user feedback
//TODO: store complete "configuration"
await event.storeToSharedPrefs();
await configuration.storeToSharedPrefs();
debugPrint('Configuration stored!');
_status = 'Login success, got all EventTypes, loaded Collection Devices & stored configuration for offline usage.';
_statusStyle = const TextStyle(color: Colors.green);
String errorText = e.toString();
errorText = errorText.substring(10, errorText.length); //Remove 'Exception' from string.
_status = errorText;
_statusStyle = const TextStyle(color: Colors.red);
setState(() {});
}
Future<void> fetchInitData() async {
try {
futureCollections = connector.fetchCollections();
await futureCollections; //wait and catch error here!
String errorText = e.toString();
errorText = errorText.substring(10, errorText.length); //Remove 'Exception' from string.
_status = errorText;
_statusStyle = const TextStyle(color: Colors.red);
}
@override
void initState() {
super.initState();
fetchInitData();
}
@override
Widget build(BuildContext context) {
final ConfigurationStoreInstance configuration = ConfigurationStoreInstance();
final EventStoreInstance events = EventStoreInstance();
appBar: AppBar(
title: const Text('Configuration'),
),
body: Container(
//constraints: const BoxConstraints.expand(),
margin: const EdgeInsets.symmetric(horizontal: 5.0),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
const SizedBox(height: 50),
const Text(
'Online access required for initial configuration!',
style: TextStyle(fontSize: 14)
),
const SizedBox(height: 50),
TextFormField(
keyboardType: TextInputType.emailAddress,
autofocus: false,
initialValue: configuration.loginInformation.mail,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'E-Mail',
hintText: '',
onChanged: (value) {
configuration.loginInformation.mail = value;
},
),
const SizedBox(height: 15.0),
TextFormField(
obscureText: true,
autofocus: false,
initialValue: configuration.loginInformation.password,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Password',
hintText: '',
onChanged: (value){
configuration.loginInformation.password = value;
},
),
const SizedBox(height: 50),
FutureBuilder<List<Collection>>(
future: futureCollections,
builder: (context, snapshot){
if (snapshot.hasData)
{
configuration.collections = [];
snapshot.data?.forEach((element) {
configuration.collections.add(element);
});
/*Initialize active collection with first received collection if not initialized yet*/
if(configuration.currentCollection.id == -1){
configuration.currentCollection = configuration.collections[0];
return DropdownButtonFormField(
value: configuration.currentCollection.collectionName,
decoration: const InputDecoration(
labelText: 'Chose Collection',
border: OutlineInputBorder(),
),
items:
configuration.collections.map((Collection collection) {
return DropdownMenuItem(
value: collection.collectionName,
child: Text(collection.collectionName),
);
}).toList(),
onChanged: (value) {
configuration.currentCollection = configuration.getCollectionFromName(value.toString());
//Fetch new selected collection devices
futureDevices = connector.fetchCollectionDevices(configuration.currentCollection.id);
}
);
if (snapshot.hasError) {
debugPrint('Some error happened');
return const CircularProgressIndicator();
}
else{
return const CircularProgressIndicator();
}
}
),
const SizedBox(height: 70.0),
TextFormField(
minLines: 1,
maxLines: 5,
readOnly: true,
autofocus: false,
enabled: false,
style: _statusStyle,
controller: TextEditingController(
text: _status,
),
margin: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 5.0),
child:Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
FloatingActionButton.extended(
heroTag: null,
tooltip: 'Export events to local .json file',
icon: const Icon(Icons.download),
label: const Text('Dump Events'),

Maximilian Betz
committed
dumpToFile(context);
//Reset for debug testing only. //Remove in RELEASE Version:
//database.delete();
//events.reset();
//configuration.reset();
},
),
FloatingActionButton.extended(
heroTag: null,
//TODO: write configuration on app dispose!
//TODO: add label prefix with appended upcounting number.
//TODO: grey out update button if nothing has changed. ?