diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/data.dart | 27 | ||||
| -rw-r--r-- | lib/db.dart | 90 | ||||
| -rw-r--r-- | lib/ui.dart | 11 |
3 files changed, 125 insertions, 3 deletions
diff --git a/lib/data.dart b/lib/data.dart index 365f5bc..ca350e5 100644 --- a/lib/data.dart +++ b/lib/data.dart @@ -1,7 +1,12 @@ +import 'dart:io'; +import 'dart:async'; + import 'package:flutter/foundation.dart'; import 'package:mqtt_client/mqtt_client.dart'; import 'package:mqtt_client/mqtt_server_client.dart'; +import 'db.dart'; + const int brokerPort = 1883; const String topicPrefix = 'sia'; @@ -22,6 +27,8 @@ enum MachineEvent { } class AppState with ChangeNotifier { + final DB db = DB(); + static const Map<MachineState, Map<MachineEvent, MachineState>> machine = <MachineState, Map<MachineEvent, MachineState>> { MachineState.init: <MachineEvent, MachineState> { MachineEvent.connect: MachineState.disconnected, @@ -46,9 +53,25 @@ class AppState with ChangeNotifier { Map<String, bool> contacts = <String, bool>{}; late MqttServerClient _client; + late Directory supportDir; String fqdn = ''; - AppState(); + AppState() { + unawaited(loadPersistence()); + } + + Future<void> loadPersistence() async { + await db.connect(); + String? dbFqdn = await db.getServerFqdn(); + if (dbFqdn == null) return; + fqdn = dbFqdn; + notifyListeners(); + } + + void setFqdn(String value) { + fqdn = value; + unawaited(db.setServerFqdn(value)); + } void process(MachineEvent event) { MachineState lastState = state; @@ -103,7 +126,7 @@ class AppState with ChangeNotifier { _client.onAutoReconnected = _onAutoReconnected; try { - _client.connect(); + unawaited(_client.connect()); } catch (e) { _client.disconnect(); return; diff --git a/lib/db.dart b/lib/db.dart new file mode 100644 index 0000000..0b2cf7a --- /dev/null +++ b/lib/db.dart @@ -0,0 +1,90 @@ +import 'dart:io'; +import 'dart:async'; + +import 'package:path_provider/path_provider.dart'; +import 'package:sqlite3/sqlite3.dart'; +import 'package:path/path.dart' as p; + +class DB { + final Completer<Database?> _dbCompleter = Completer<Database?>(); + static const List<String> migrations = <String>[ + ''' +PRAGMA user_version = 1; +CREATE TABLE "key_value" ( + "key" TEXT NOT NULL UNIQUE, + "value" TEXT, + PRIMARY KEY("key") +); + ''', + ]; + + Future<void> connect() async { + String path = await _getDbPath(); + Database candidate = sqlite3.open(path); + + migrate(candidate); + + _dbCompleter.complete(candidate); + } + + void dispose() async { + if (_dbCompleter.isCompleted == false) { + return; + } + Database? db = await _dbCompleter.future; + if (db == null) return; + db.close(); + } + + static Future<String> _getDbPath() async { + Directory supportDir = await getApplicationSupportDirectory(); + return p.join(supportDir.path, 'main.sqlite3'); + } + + static void migrate(Database db) { + for (int i=0; i<migrations.length; i++) { + int? userVersion = _getUserVersion(db); + if (userVersion == null) return; + + if (i == userVersion) { + db.execute(migrations[i]); + } + } + } + + static int? _getUserVersion(Database db) { + ResultSet result = db.select('PRAGMA user_version;'); + if (result.length != 1) return null; + return result.first.values.first as int; + } + + Future<String?> getServerFqdn() async { + Database? db = await _dbCompleter.future; + if (db == null) return null; + + ResultSet result = db.select( + 'SELECT value FROM key_value WHERE key = \'server_fqdn\';' + ); + if (result.length != 1) return null; + + return result[0]['value']; + } + + Future<void> setServerFqdn(String value) async { + Database? db = await _dbCompleter.future; + if (db == null) return; + + String? current = await getServerFqdn(); + if (current == null) { + db.execute( + 'INSERT INTO key_value (key, value) VALUES (\'server_fqdn\', ?);', + <Object?>[value], + ); + } else { + db.execute( + 'UPDATE key_value SET value = ? WHERE key = \'server_fqdn\';', + <Object?>[value], + ); + } + } +} diff --git a/lib/ui.dart b/lib/ui.dart index 9603562..3a98be9 100644 --- a/lib/ui.dart +++ b/lib/ui.dart @@ -41,8 +41,17 @@ class _ConnectionPageState extends State<ConnectionPage> { final AppState provider = context.read<AppState>(); controller = TextEditingController(text: provider.fqdn); + provider.addListener(() { + if (controller.text != provider.fqdn) { + controller.text = provider.fqdn; + controller.selection = TextSelection.fromPosition( + TextPosition(offset: controller.text.length), + ); + } + }); + controller.addListener(() { - provider.fqdn = controller.text; + provider.setFqdn(controller.text); }); } |
