import 'dart:io'; import 'package:drift/drift.dart'; import 'package:drift/native.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; import '../../transport/connection_type.dart'; part 'app_database.g.dart'; /// Persistenz fuer Missionen (Architektur-Doku 4.15): Drift statt Hive, weil /// indexierte Abfragen (Suche nach Name/Ort/Datum) benoetigt werden und das /// Schema kompatibel zu einem kuenftigen lokal-first Server-Sync-Muster /// (Dirty-Flags, Server-IDs) bleiben soll. class Missions extends Table { IntColumn get id => integer().autoIncrement()(); TextColumn get name => text()(); TextColumn get location => text().nullable()(); DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)(); DateTimeColumn get updatedAt => dateTime().withDefault(currentDateAndTime)(); TextColumn get waypointsJson => text()(); BoolColumn get isDirty => boolean().withDefault(const Constant(true))(); TextColumn get serverId => text().nullable()(); } /// Drohnen-Profile (Doku 3.5/7.3) - FC-Typ bewusst nicht Teil des Schemas, /// siehe DroneProfile-Domainklasse. class DroneProfiles extends Table { IntColumn get id => integer().autoIncrement()(); TextColumn get name => text()(); RealColumn get minSpeed => real()(); RealColumn get cruiseSpeed => real()(); RealColumn get maxSpeed => real()(); RealColumn get minTurnRadius => real()(); RealColumn get loiterRadius => real()(); RealColumn get catchRadius => real()(); RealColumn get maxClimbRate => real()(); RealColumn get maxDescentRate => real()(); RealColumn get maxRangeM => real()(); RealColumn get maxEnduranceMin => real()(); RealColumn get maxAltitudeM => real()(); } /// Einzeilige Einstellungstabelle (id fest 0) fuer app-weite Auswahl, die /// einen Neustart ueberleben soll: zuletzt aktives Drohnenprofil, die /// zuletzt bearbeitete (autosaved) Mission, um sie beim naechsten Start /// fortzusetzen (Doku 7.5: Autosave/Mission-Drafts), sowie die /// Verbindungseinstellungen (Doku Kommunikationsschicht Abschnitt 7). class AppSettingsTable extends Table { IntColumn get id => integer()(); IntColumn get activeDroneProfileId => integer().nullable()(); IntColumn get currentMissionId => integer().nullable()(); /// Gemerkte MAC-Adresse des Bluetooth-Zielgeraets (Doku Kommunikations- /// schicht 3.2a) - entweder manuell gewaehlt oder automatisch anhand des /// "mLRS"-Namenspraefix aufgeloest. TextColumn get connectionDeviceAddress => text().nullable()(); /// "Beim Wechsel in Fly automatisch verbinden" (Doku 7), Standard an. BoolColumn get connectionAutoConnect => boolean().withDefault(const Constant(true))(); /// Gewaehlte Verbindungsart (Doku 7: "Art: WLAN * USB (spaeter)"), /// gespeichert als [ConnectionType.name]. App-Default ist WLAN; die /// Nutzerauswahl wird danach dauerhaft gemerkt. TextColumn get connectionType => text().withDefault(const Constant('wifi'))(); /// Vom Nutzer eingetragene Ziel-IP der mLRS-WLAN-Bruecke (Doku 3: /// "Zieladresse niemals fest eincodieren") - null, solange keine Vorgabe /// gesetzt ist und die Gegenstelle erst aus dem Verkehr gelernt wird. TextColumn get connectionWifiHost => text().nullable()(); /// Lokaler UDP-Port fuer die mLRS-WLAN-Bruecke (Doku 3), Standard 14550. IntColumn get connectionWifiPort => integer().withDefault(const Constant(kDefaultWifiPort))(); @override Set get primaryKey => {id}; } @DriftDatabase(tables: [Missions, DroneProfiles, AppSettingsTable]) class AppDatabase extends _$AppDatabase { AppDatabase() : super(_openConnection()); AppDatabase.forTesting(super.executor); @override int get schemaVersion => 4; @override MigrationStrategy get migration => MigrationStrategy( onCreate: (m) => m.createAll(), onUpgrade: (m, from, to) async { if (from < 2) { await m.addColumn(missions, missions.updatedAt); await m.createTable(droneProfiles); await m.createTable(appSettingsTable); } if (from < 3) { await m.addColumn( appSettingsTable, appSettingsTable.connectionDeviceAddress, ); await m.addColumn( appSettingsTable, appSettingsTable.connectionAutoConnect, ); } if (from < 4) { await m.addColumn(appSettingsTable, appSettingsTable.connectionType); await m.addColumn( appSettingsTable, appSettingsTable.connectionWifiHost, ); await m.addColumn( appSettingsTable, appSettingsTable.connectionWifiPort, ); } }, ); static LazyDatabase _openConnection() { return LazyDatabase(() async { final dbFolder = await getApplicationDocumentsDirectory(); final file = File(p.join(dbFolder.path, 'dmc_missions.sqlite')); return NativeDatabase.createInBackground(file); }); } }