bluetooth connectivity layer added

This commit is contained in:
Constantin Leue
2026-07-30 19:46:52 +02:00
parent 310d92f187
commit 5994aee7ad
19 changed files with 1665 additions and 15 deletions
+23 -3
View File
@@ -43,14 +43,24 @@ class DroneProfiles extends Table {
}
/// Einzeilige Einstellungstabelle (id fest 0) fuer app-weite Auswahl, die
/// einen Neustart ueberleben soll: zuletzt aktives Drohnenprofil und 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).
/// 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))();
@override
Set<Column> get primaryKey => {id};
}
@@ -62,7 +72,7 @@ class AppDatabase extends _$AppDatabase {
AppDatabase.forTesting(super.executor);
@override
int get schemaVersion => 2;
int get schemaVersion => 3;
@override
MigrationStrategy get migration => MigrationStrategy(
@@ -73,6 +83,16 @@ class AppDatabase extends _$AppDatabase {
await m.createTable(droneProfiles);
await m.createTable(appSettingsTable);
}
if (from < 3) {
await m.addColumn(
appSettingsTable,
appSettingsTable.connectionDeviceAddress,
);
await m.addColumn(
appSettingsTable,
appSettingsTable.connectionAutoConnect,
);
}
},
);
+182 -4
View File
@@ -1322,11 +1322,39 @@ class $AppSettingsTableTable extends AppSettingsTable
type: DriftSqlType.int,
requiredDuringInsert: false,
);
static const VerificationMeta _connectionDeviceAddressMeta =
const VerificationMeta('connectionDeviceAddress');
@override
late final GeneratedColumn<String> connectionDeviceAddress =
GeneratedColumn<String>(
'connection_device_address',
aliasedName,
true,
type: DriftSqlType.string,
requiredDuringInsert: false,
);
static const VerificationMeta _connectionAutoConnectMeta =
const VerificationMeta('connectionAutoConnect');
@override
late final GeneratedColumn<bool> connectionAutoConnect =
GeneratedColumn<bool>(
'connection_auto_connect',
aliasedName,
false,
type: DriftSqlType.bool,
requiredDuringInsert: false,
defaultConstraints: GeneratedColumn.constraintIsAlways(
'CHECK ("connection_auto_connect" IN (0, 1))',
),
defaultValue: const Constant(true),
);
@override
List<GeneratedColumn> get $columns => [
id,
activeDroneProfileId,
currentMissionId,
connectionDeviceAddress,
connectionAutoConnect,
];
@override
String get aliasedName => _alias ?? actualTableName;
@@ -1361,6 +1389,24 @@ class $AppSettingsTableTable extends AppSettingsTable
),
);
}
if (data.containsKey('connection_device_address')) {
context.handle(
_connectionDeviceAddressMeta,
connectionDeviceAddress.isAcceptableOrUnknown(
data['connection_device_address']!,
_connectionDeviceAddressMeta,
),
);
}
if (data.containsKey('connection_auto_connect')) {
context.handle(
_connectionAutoConnectMeta,
connectionAutoConnect.isAcceptableOrUnknown(
data['connection_auto_connect']!,
_connectionAutoConnectMeta,
),
);
}
return context;
}
@@ -1382,6 +1428,14 @@ class $AppSettingsTableTable extends AppSettingsTable
DriftSqlType.int,
data['${effectivePrefix}current_mission_id'],
),
connectionDeviceAddress: attachedDatabase.typeMapping.read(
DriftSqlType.string,
data['${effectivePrefix}connection_device_address'],
),
connectionAutoConnect: attachedDatabase.typeMapping.read(
DriftSqlType.bool,
data['${effectivePrefix}connection_auto_connect'],
)!,
);
}
@@ -1396,10 +1450,20 @@ class AppSettingsTableData extends DataClass
final int id;
final int? activeDroneProfileId;
final int? currentMissionId;
/// Gemerkte MAC-Adresse des Bluetooth-Zielgeraets (Doku Kommunikations-
/// schicht 3.2a) - entweder manuell gewaehlt oder automatisch anhand des
/// "mLRS"-Namenspraefix aufgeloest.
final String? connectionDeviceAddress;
/// "Beim Wechsel in Fly automatisch verbinden" (Doku 7), Standard an.
final bool connectionAutoConnect;
const AppSettingsTableData({
required this.id,
this.activeDroneProfileId,
this.currentMissionId,
this.connectionDeviceAddress,
required this.connectionAutoConnect,
});
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
@@ -1411,6 +1475,12 @@ class AppSettingsTableData extends DataClass
if (!nullToAbsent || currentMissionId != null) {
map['current_mission_id'] = Variable<int>(currentMissionId);
}
if (!nullToAbsent || connectionDeviceAddress != null) {
map['connection_device_address'] = Variable<String>(
connectionDeviceAddress,
);
}
map['connection_auto_connect'] = Variable<bool>(connectionAutoConnect);
return map;
}
@@ -1423,6 +1493,10 @@ class AppSettingsTableData extends DataClass
currentMissionId: currentMissionId == null && nullToAbsent
? const Value.absent()
: Value(currentMissionId),
connectionDeviceAddress: connectionDeviceAddress == null && nullToAbsent
? const Value.absent()
: Value(connectionDeviceAddress),
connectionAutoConnect: Value(connectionAutoConnect),
);
}
@@ -1437,6 +1511,12 @@ class AppSettingsTableData extends DataClass
json['activeDroneProfileId'],
),
currentMissionId: serializer.fromJson<int?>(json['currentMissionId']),
connectionDeviceAddress: serializer.fromJson<String?>(
json['connectionDeviceAddress'],
),
connectionAutoConnect: serializer.fromJson<bool>(
json['connectionAutoConnect'],
),
);
}
@override
@@ -1446,6 +1526,10 @@ class AppSettingsTableData extends DataClass
'id': serializer.toJson<int>(id),
'activeDroneProfileId': serializer.toJson<int?>(activeDroneProfileId),
'currentMissionId': serializer.toJson<int?>(currentMissionId),
'connectionDeviceAddress': serializer.toJson<String?>(
connectionDeviceAddress,
),
'connectionAutoConnect': serializer.toJson<bool>(connectionAutoConnect),
};
}
@@ -1453,6 +1537,8 @@ class AppSettingsTableData extends DataClass
int? id,
Value<int?> activeDroneProfileId = const Value.absent(),
Value<int?> currentMissionId = const Value.absent(),
Value<String?> connectionDeviceAddress = const Value.absent(),
bool? connectionAutoConnect,
}) => AppSettingsTableData(
id: id ?? this.id,
activeDroneProfileId: activeDroneProfileId.present
@@ -1461,6 +1547,10 @@ class AppSettingsTableData extends DataClass
currentMissionId: currentMissionId.present
? currentMissionId.value
: this.currentMissionId,
connectionDeviceAddress: connectionDeviceAddress.present
? connectionDeviceAddress.value
: this.connectionDeviceAddress,
connectionAutoConnect: connectionAutoConnect ?? this.connectionAutoConnect,
);
AppSettingsTableData copyWithCompanion(AppSettingsTableCompanion data) {
return AppSettingsTableData(
@@ -1471,6 +1561,12 @@ class AppSettingsTableData extends DataClass
currentMissionId: data.currentMissionId.present
? data.currentMissionId.value
: this.currentMissionId,
connectionDeviceAddress: data.connectionDeviceAddress.present
? data.connectionDeviceAddress.value
: this.connectionDeviceAddress,
connectionAutoConnect: data.connectionAutoConnect.present
? data.connectionAutoConnect.value
: this.connectionAutoConnect,
);
}
@@ -1479,46 +1575,68 @@ class AppSettingsTableData extends DataClass
return (StringBuffer('AppSettingsTableData(')
..write('id: $id, ')
..write('activeDroneProfileId: $activeDroneProfileId, ')
..write('currentMissionId: $currentMissionId')
..write('currentMissionId: $currentMissionId, ')
..write('connectionDeviceAddress: $connectionDeviceAddress, ')
..write('connectionAutoConnect: $connectionAutoConnect')
..write(')'))
.toString();
}
@override
int get hashCode => Object.hash(id, activeDroneProfileId, currentMissionId);
int get hashCode => Object.hash(
id,
activeDroneProfileId,
currentMissionId,
connectionDeviceAddress,
connectionAutoConnect,
);
@override
bool operator ==(Object other) =>
identical(this, other) ||
(other is AppSettingsTableData &&
other.id == this.id &&
other.activeDroneProfileId == this.activeDroneProfileId &&
other.currentMissionId == this.currentMissionId);
other.currentMissionId == this.currentMissionId &&
other.connectionDeviceAddress == this.connectionDeviceAddress &&
other.connectionAutoConnect == this.connectionAutoConnect);
}
class AppSettingsTableCompanion extends UpdateCompanion<AppSettingsTableData> {
final Value<int> id;
final Value<int?> activeDroneProfileId;
final Value<int?> currentMissionId;
final Value<String?> connectionDeviceAddress;
final Value<bool> connectionAutoConnect;
const AppSettingsTableCompanion({
this.id = const Value.absent(),
this.activeDroneProfileId = const Value.absent(),
this.currentMissionId = const Value.absent(),
this.connectionDeviceAddress = const Value.absent(),
this.connectionAutoConnect = const Value.absent(),
});
AppSettingsTableCompanion.insert({
this.id = const Value.absent(),
this.activeDroneProfileId = const Value.absent(),
this.currentMissionId = const Value.absent(),
this.connectionDeviceAddress = const Value.absent(),
this.connectionAutoConnect = const Value.absent(),
});
static Insertable<AppSettingsTableData> custom({
Expression<int>? id,
Expression<int>? activeDroneProfileId,
Expression<int>? currentMissionId,
Expression<String>? connectionDeviceAddress,
Expression<bool>? connectionAutoConnect,
}) {
return RawValuesInsertable({
if (id != null) 'id': id,
if (activeDroneProfileId != null)
'active_drone_profile_id': activeDroneProfileId,
if (currentMissionId != null) 'current_mission_id': currentMissionId,
if (connectionDeviceAddress != null)
'connection_device_address': connectionDeviceAddress,
if (connectionAutoConnect != null)
'connection_auto_connect': connectionAutoConnect,
});
}
@@ -1526,11 +1644,17 @@ class AppSettingsTableCompanion extends UpdateCompanion<AppSettingsTableData> {
Value<int>? id,
Value<int?>? activeDroneProfileId,
Value<int?>? currentMissionId,
Value<String?>? connectionDeviceAddress,
Value<bool>? connectionAutoConnect,
}) {
return AppSettingsTableCompanion(
id: id ?? this.id,
activeDroneProfileId: activeDroneProfileId ?? this.activeDroneProfileId,
currentMissionId: currentMissionId ?? this.currentMissionId,
connectionDeviceAddress:
connectionDeviceAddress ?? this.connectionDeviceAddress,
connectionAutoConnect:
connectionAutoConnect ?? this.connectionAutoConnect,
);
}
@@ -1548,6 +1672,16 @@ class AppSettingsTableCompanion extends UpdateCompanion<AppSettingsTableData> {
if (currentMissionId.present) {
map['current_mission_id'] = Variable<int>(currentMissionId.value);
}
if (connectionDeviceAddress.present) {
map['connection_device_address'] = Variable<String>(
connectionDeviceAddress.value,
);
}
if (connectionAutoConnect.present) {
map['connection_auto_connect'] = Variable<bool>(
connectionAutoConnect.value,
);
}
return map;
}
@@ -1556,7 +1690,9 @@ class AppSettingsTableCompanion extends UpdateCompanion<AppSettingsTableData> {
return (StringBuffer('AppSettingsTableCompanion(')
..write('id: $id, ')
..write('activeDroneProfileId: $activeDroneProfileId, ')
..write('currentMissionId: $currentMissionId')
..write('currentMissionId: $currentMissionId, ')
..write('connectionDeviceAddress: $connectionDeviceAddress, ')
..write('connectionAutoConnect: $connectionAutoConnect')
..write(')'))
.toString();
}
@@ -2195,12 +2331,16 @@ typedef $$AppSettingsTableTableCreateCompanionBuilder =
Value<int> id,
Value<int?> activeDroneProfileId,
Value<int?> currentMissionId,
Value<String?> connectionDeviceAddress,
Value<bool> connectionAutoConnect,
});
typedef $$AppSettingsTableTableUpdateCompanionBuilder =
AppSettingsTableCompanion Function({
Value<int> id,
Value<int?> activeDroneProfileId,
Value<int?> currentMissionId,
Value<String?> connectionDeviceAddress,
Value<bool> connectionAutoConnect,
});
class $$AppSettingsTableTableFilterComposer
@@ -2226,6 +2366,16 @@ class $$AppSettingsTableTableFilterComposer
column: $table.currentMissionId,
builder: (column) => ColumnFilters(column),
);
ColumnFilters<String> get connectionDeviceAddress => $composableBuilder(
column: $table.connectionDeviceAddress,
builder: (column) => ColumnFilters(column),
);
ColumnFilters<bool> get connectionAutoConnect => $composableBuilder(
column: $table.connectionAutoConnect,
builder: (column) => ColumnFilters(column),
);
}
class $$AppSettingsTableTableOrderingComposer
@@ -2251,6 +2401,16 @@ class $$AppSettingsTableTableOrderingComposer
column: $table.currentMissionId,
builder: (column) => ColumnOrderings(column),
);
ColumnOrderings<String> get connectionDeviceAddress => $composableBuilder(
column: $table.connectionDeviceAddress,
builder: (column) => ColumnOrderings(column),
);
ColumnOrderings<bool> get connectionAutoConnect => $composableBuilder(
column: $table.connectionAutoConnect,
builder: (column) => ColumnOrderings(column),
);
}
class $$AppSettingsTableTableAnnotationComposer
@@ -2274,6 +2434,16 @@ class $$AppSettingsTableTableAnnotationComposer
column: $table.currentMissionId,
builder: (column) => column,
);
GeneratedColumn<String> get connectionDeviceAddress => $composableBuilder(
column: $table.connectionDeviceAddress,
builder: (column) => column,
);
GeneratedColumn<bool> get connectionAutoConnect => $composableBuilder(
column: $table.connectionAutoConnect,
builder: (column) => column,
);
}
class $$AppSettingsTableTableTableManager
@@ -2316,20 +2486,28 @@ class $$AppSettingsTableTableTableManager
Value<int> id = const Value.absent(),
Value<int?> activeDroneProfileId = const Value.absent(),
Value<int?> currentMissionId = const Value.absent(),
Value<String?> connectionDeviceAddress = const Value.absent(),
Value<bool> connectionAutoConnect = const Value.absent(),
}) => AppSettingsTableCompanion(
id: id,
activeDroneProfileId: activeDroneProfileId,
currentMissionId: currentMissionId,
connectionDeviceAddress: connectionDeviceAddress,
connectionAutoConnect: connectionAutoConnect,
),
createCompanionCallback:
({
Value<int> id = const Value.absent(),
Value<int?> activeDroneProfileId = const Value.absent(),
Value<int?> currentMissionId = const Value.absent(),
Value<String?> connectionDeviceAddress = const Value.absent(),
Value<bool> connectionAutoConnect = const Value.absent(),
}) => AppSettingsTableCompanion.insert(
id: id,
activeDroneProfileId: activeDroneProfileId,
currentMissionId: currentMissionId,
connectionDeviceAddress: connectionDeviceAddress,
connectionAutoConnect: connectionAutoConnect,
),
withReferenceMapper: (p0) => p0
.map((e) => (e.readTable(table), BaseReferences(db, table, e)))
@@ -12,13 +12,21 @@ class AppSettingsRepository {
static const _rowId = 0;
Future<({int? activeDroneProfileId, int? currentMissionId})> load() async {
Future<
({
int? activeDroneProfileId,
int? currentMissionId,
String? connectionDeviceAddress,
bool connectionAutoConnect,
})> load() async {
final row = await (_db.select(_db.appSettingsTable)
..where((s) => s.id.equals(_rowId)))
.getSingleOrNull();
return (
activeDroneProfileId: row?.activeDroneProfileId,
currentMissionId: row?.currentMissionId,
connectionDeviceAddress: row?.connectionDeviceAddress,
connectionAutoConnect: row?.connectionAutoConnect ?? true,
);
}
@@ -36,6 +44,26 @@ class AppSettingsRepository {
));
}
/// Gemerkte Bluetooth-MAC-Adresse (Doku Kommunikationsschicht 3.2a), oder
/// null um die Erinnerung zu loeschen (z.B. nach "Geraet entkoppeln").
Future<String?> loadConnectionDeviceAddress() async =>
(await load()).connectionDeviceAddress;
Future<void> setConnectionDeviceAddress(String? address) async {
await _upsert(AppSettingsTableCompanion(
id: const Value(_rowId),
connectionDeviceAddress: Value(address),
));
}
/// "Beim Wechsel in Fly automatisch verbinden" (Doku 7), Standard an.
Future<void> setConnectionAutoConnect(bool value) async {
await _upsert(AppSettingsTableCompanion(
id: const Value(_rowId),
connectionAutoConnect: Value(value),
));
}
Future<void> _upsert(AppSettingsTableCompanion companion) async {
await _db.into(_db.appSettingsTable).insertOnConflictUpdate(companion);
}