autoconnect on fly mode (does not work yet)
This commit is contained in:
@@ -6,6 +6,7 @@ import android.net.LinkProperties
|
|||||||
import android.net.Network
|
import android.net.Network
|
||||||
import android.net.NetworkCapabilities
|
import android.net.NetworkCapabilities
|
||||||
import android.net.NetworkRequest
|
import android.net.NetworkRequest
|
||||||
|
import android.net.wifi.WifiInfo
|
||||||
import android.net.wifi.WifiManager
|
import android.net.wifi.WifiManager
|
||||||
import android.net.wifi.WifiNetworkSpecifier
|
import android.net.wifi.WifiNetworkSpecifier
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
@@ -101,7 +102,8 @@ class MlrsNetworkPlugin(
|
|||||||
result.error("invalid_argument", "ssidPrefix darf nicht leer sein", null)
|
result.error("invalid_argument", "ssidPrefix darf nicht leer sein", null)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
requestNetwork(ssidPrefix)
|
val exactSsid = call.argument<String>("exactSsid")
|
||||||
|
requestNetwork(ssidPrefix, exactSsid)
|
||||||
result.success(null)
|
result.success(null)
|
||||||
}
|
}
|
||||||
"releaseNetwork" -> {
|
"releaseNetwork" -> {
|
||||||
@@ -133,14 +135,24 @@ class MlrsNetworkPlugin(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun requestNetwork(ssidPrefix: String) {
|
private fun requestNetwork(ssidPrefix: String, exactSsid: String?) {
|
||||||
// Vorherigen Callback zuerst abmelden - sonst haeuften sich bei
|
// Vorherigen Callback zuerst abmelden - sonst haeuften sich bei
|
||||||
// mehrfachem Connect-Versuch mehrere registrierte Callbacks an.
|
// mehrfachem Connect-Versuch mehrere registrierte Callbacks an.
|
||||||
releaseNetwork()
|
releaseNetwork()
|
||||||
|
|
||||||
val specifier = WifiNetworkSpecifier.Builder()
|
// Ist eine zuvor erfolgreich verbundene SSID bekannt, exakt statt per
|
||||||
.setSsidPattern(PatternMatcher(ssidPrefix, PatternMatcher.PATTERN_PREFIX))
|
// Praefix anfragen: Android merkt sich die Nutzerzustimmung nur fuer
|
||||||
.build()
|
// exakte WifiNetworkSpecifier-Treffer und kann dann kuenftig ohne
|
||||||
|
// erneuten Systemdialog automatisch verbinden. Praefix-Anfragen
|
||||||
|
// zeigen dagegen praktisch immer den Dialog, weil die aufgeloeste
|
||||||
|
// SSID (zufaellige Endung) sich aendern koennte.
|
||||||
|
val specifierBuilder = WifiNetworkSpecifier.Builder()
|
||||||
|
if (!exactSsid.isNullOrEmpty()) {
|
||||||
|
specifierBuilder.setSsid(exactSsid)
|
||||||
|
} else {
|
||||||
|
specifierBuilder.setSsidPattern(PatternMatcher(ssidPrefix, PatternMatcher.PATTERN_PREFIX))
|
||||||
|
}
|
||||||
|
val specifier = specifierBuilder.build()
|
||||||
|
|
||||||
val request = NetworkRequest.Builder()
|
val request = NetworkRequest.Builder()
|
||||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||||
@@ -152,8 +164,9 @@ class MlrsNetworkPlugin(
|
|||||||
override fun onAvailable(network: Network) {
|
override fun onAvailable(network: Network) {
|
||||||
currentNetwork = network
|
currentNetwork = network
|
||||||
val gateway = gatewayAddressOf(connectivityManager.getLinkProperties(network))
|
val gateway = gatewayAddressOf(connectivityManager.getLinkProperties(network))
|
||||||
|
val ssid = ssidOf(connectivityManager.getNetworkCapabilities(network))
|
||||||
eventSink?.success(
|
eventSink?.success(
|
||||||
mapOf("type" to "available", "gatewayAddress" to gateway),
|
mapOf("type" to "available", "gatewayAddress" to gateway, "ssid" to ssid),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +202,20 @@ class MlrsNetworkPlugin(
|
|||||||
return route?.gateway?.hostAddress
|
return route?.gateway?.hostAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ermittelt die tatsaechliche SSID des verbundenen Netzes. Erfordert
|
||||||
|
* normalerweise ACCESS_FINE_LOCATION, ausser fuer die anfragende App
|
||||||
|
* selbst bei einem ueber WifiNetworkSpecifier bewilligten Netz - genau
|
||||||
|
* unser Fall, siehe `WifiInfo.getSSID()`-Dokumentation.
|
||||||
|
*/
|
||||||
|
private fun ssidOf(capabilities: NetworkCapabilities?): String? {
|
||||||
|
val wifiInfo = capabilities?.transportInfo as? WifiInfo ?: return null
|
||||||
|
val ssid = wifiInfo.ssid
|
||||||
|
if (ssid.isNullOrEmpty() || ssid == WifiManager.UNKNOWN_SSID) return null
|
||||||
|
// WifiInfo.getSSID() liefert UTF-8-SSIDs in Anfuehrungszeichen.
|
||||||
|
return ssid.removeSurrounding("\"")
|
||||||
|
}
|
||||||
|
|
||||||
private fun isStaConcurrencySupported(): Boolean? {
|
private fun isStaConcurrencySupported(): Boolean? {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return null
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return null
|
||||||
val wifiManager =
|
val wifiManager =
|
||||||
|
|||||||
@@ -84,6 +84,13 @@ class AppSettingsTable extends Table {
|
|||||||
TextColumn get connectionWifiSsidPrefix =>
|
TextColumn get connectionWifiSsidPrefix =>
|
||||||
text().withDefault(const Constant(kDefaultWifiSsidPrefix))();
|
text().withDefault(const Constant(kDefaultWifiSsidPrefix))();
|
||||||
|
|
||||||
|
/// Exakte SSID der zuletzt erfolgreich verbundenen mLRS-Bruecke (Doku
|
||||||
|
/// Abschnitt 8: "verbundenes WLAN merken") - null, solange noch nie
|
||||||
|
/// erfolgreich verbunden wurde. Wird fuer kuenftige Verbindungsversuche
|
||||||
|
/// als exakter WifiNetworkSpecifier statt Praefix verwendet, damit Android
|
||||||
|
/// ohne erneuten Systemdialog automatisch verbinden kann.
|
||||||
|
TextColumn get connectionWifiLastSsid => text().nullable()();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Set<Column> get primaryKey => {id};
|
Set<Column> get primaryKey => {id};
|
||||||
}
|
}
|
||||||
@@ -95,7 +102,7 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
AppDatabase.forTesting(super.executor);
|
AppDatabase.forTesting(super.executor);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 5;
|
int get schemaVersion => 6;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MigrationStrategy get migration => MigrationStrategy(
|
MigrationStrategy get migration => MigrationStrategy(
|
||||||
@@ -133,6 +140,12 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
appSettingsTable.connectionWifiSsidPrefix,
|
appSettingsTable.connectionWifiSsidPrefix,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (from < 6) {
|
||||||
|
await m.addColumn(
|
||||||
|
appSettingsTable,
|
||||||
|
appSettingsTable.connectionWifiLastSsid,
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1394,6 +1394,17 @@ class $AppSettingsTableTable extends AppSettingsTable
|
|||||||
requiredDuringInsert: false,
|
requiredDuringInsert: false,
|
||||||
defaultValue: const Constant(kDefaultWifiSsidPrefix),
|
defaultValue: const Constant(kDefaultWifiSsidPrefix),
|
||||||
);
|
);
|
||||||
|
static const VerificationMeta _connectionWifiLastSsidMeta =
|
||||||
|
const VerificationMeta('connectionWifiLastSsid');
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<String> connectionWifiLastSsid =
|
||||||
|
GeneratedColumn<String>(
|
||||||
|
'connection_wifi_last_ssid',
|
||||||
|
aliasedName,
|
||||||
|
true,
|
||||||
|
type: DriftSqlType.string,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
);
|
||||||
@override
|
@override
|
||||||
List<GeneratedColumn> get $columns => [
|
List<GeneratedColumn> get $columns => [
|
||||||
id,
|
id,
|
||||||
@@ -1405,6 +1416,7 @@ class $AppSettingsTableTable extends AppSettingsTable
|
|||||||
connectionWifiHost,
|
connectionWifiHost,
|
||||||
connectionWifiPort,
|
connectionWifiPort,
|
||||||
connectionWifiSsidPrefix,
|
connectionWifiSsidPrefix,
|
||||||
|
connectionWifiLastSsid,
|
||||||
];
|
];
|
||||||
@override
|
@override
|
||||||
String get aliasedName => _alias ?? actualTableName;
|
String get aliasedName => _alias ?? actualTableName;
|
||||||
@@ -1493,6 +1505,15 @@ class $AppSettingsTableTable extends AppSettingsTable
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (data.containsKey('connection_wifi_last_ssid')) {
|
||||||
|
context.handle(
|
||||||
|
_connectionWifiLastSsidMeta,
|
||||||
|
connectionWifiLastSsid.isAcceptableOrUnknown(
|
||||||
|
data['connection_wifi_last_ssid']!,
|
||||||
|
_connectionWifiLastSsidMeta,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1538,6 +1559,10 @@ class $AppSettingsTableTable extends AppSettingsTable
|
|||||||
DriftSqlType.string,
|
DriftSqlType.string,
|
||||||
data['${effectivePrefix}connection_wifi_ssid_prefix'],
|
data['${effectivePrefix}connection_wifi_ssid_prefix'],
|
||||||
)!,
|
)!,
|
||||||
|
connectionWifiLastSsid: attachedDatabase.typeMapping.read(
|
||||||
|
DriftSqlType.string,
|
||||||
|
data['${effectivePrefix}connection_wifi_last_ssid'],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1578,6 +1603,13 @@ class AppSettingsTableData extends DataClass
|
|||||||
/// `WifiNetworkSpecifier` (Doku Kommunikationsschicht v2 Abschnitt 4/8),
|
/// `WifiNetworkSpecifier` (Doku Kommunikationsschicht v2 Abschnitt 4/8),
|
||||||
/// Standard "mLRS-", ueberschreibbar.
|
/// Standard "mLRS-", ueberschreibbar.
|
||||||
final String connectionWifiSsidPrefix;
|
final String connectionWifiSsidPrefix;
|
||||||
|
|
||||||
|
/// Exakte SSID der zuletzt erfolgreich verbundenen mLRS-Bruecke (Doku
|
||||||
|
/// Abschnitt 8: "verbundenes WLAN merken") - null, solange noch nie
|
||||||
|
/// erfolgreich verbunden wurde. Wird fuer kuenftige Verbindungsversuche
|
||||||
|
/// als exakter WifiNetworkSpecifier statt Praefix verwendet, damit Android
|
||||||
|
/// ohne erneuten Systemdialog automatisch verbinden kann.
|
||||||
|
final String? connectionWifiLastSsid;
|
||||||
const AppSettingsTableData({
|
const AppSettingsTableData({
|
||||||
required this.id,
|
required this.id,
|
||||||
this.activeDroneProfileId,
|
this.activeDroneProfileId,
|
||||||
@@ -1588,6 +1620,7 @@ class AppSettingsTableData extends DataClass
|
|||||||
this.connectionWifiHost,
|
this.connectionWifiHost,
|
||||||
required this.connectionWifiPort,
|
required this.connectionWifiPort,
|
||||||
required this.connectionWifiSsidPrefix,
|
required this.connectionWifiSsidPrefix,
|
||||||
|
this.connectionWifiLastSsid,
|
||||||
});
|
});
|
||||||
@override
|
@override
|
||||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||||
@@ -1613,6 +1646,11 @@ class AppSettingsTableData extends DataClass
|
|||||||
map['connection_wifi_ssid_prefix'] = Variable<String>(
|
map['connection_wifi_ssid_prefix'] = Variable<String>(
|
||||||
connectionWifiSsidPrefix,
|
connectionWifiSsidPrefix,
|
||||||
);
|
);
|
||||||
|
if (!nullToAbsent || connectionWifiLastSsid != null) {
|
||||||
|
map['connection_wifi_last_ssid'] = Variable<String>(
|
||||||
|
connectionWifiLastSsid,
|
||||||
|
);
|
||||||
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1635,6 +1673,9 @@ class AppSettingsTableData extends DataClass
|
|||||||
: Value(connectionWifiHost),
|
: Value(connectionWifiHost),
|
||||||
connectionWifiPort: Value(connectionWifiPort),
|
connectionWifiPort: Value(connectionWifiPort),
|
||||||
connectionWifiSsidPrefix: Value(connectionWifiSsidPrefix),
|
connectionWifiSsidPrefix: Value(connectionWifiSsidPrefix),
|
||||||
|
connectionWifiLastSsid: connectionWifiLastSsid == null && nullToAbsent
|
||||||
|
? const Value.absent()
|
||||||
|
: Value(connectionWifiLastSsid),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1663,6 +1704,9 @@ class AppSettingsTableData extends DataClass
|
|||||||
connectionWifiSsidPrefix: serializer.fromJson<String>(
|
connectionWifiSsidPrefix: serializer.fromJson<String>(
|
||||||
json['connectionWifiSsidPrefix'],
|
json['connectionWifiSsidPrefix'],
|
||||||
),
|
),
|
||||||
|
connectionWifiLastSsid: serializer.fromJson<String?>(
|
||||||
|
json['connectionWifiLastSsid'],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@override
|
@override
|
||||||
@@ -1682,6 +1726,9 @@ class AppSettingsTableData extends DataClass
|
|||||||
'connectionWifiSsidPrefix': serializer.toJson<String>(
|
'connectionWifiSsidPrefix': serializer.toJson<String>(
|
||||||
connectionWifiSsidPrefix,
|
connectionWifiSsidPrefix,
|
||||||
),
|
),
|
||||||
|
'connectionWifiLastSsid': serializer.toJson<String?>(
|
||||||
|
connectionWifiLastSsid,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1695,6 +1742,7 @@ class AppSettingsTableData extends DataClass
|
|||||||
Value<String?> connectionWifiHost = const Value.absent(),
|
Value<String?> connectionWifiHost = const Value.absent(),
|
||||||
int? connectionWifiPort,
|
int? connectionWifiPort,
|
||||||
String? connectionWifiSsidPrefix,
|
String? connectionWifiSsidPrefix,
|
||||||
|
Value<String?> connectionWifiLastSsid = const Value.absent(),
|
||||||
}) => AppSettingsTableData(
|
}) => AppSettingsTableData(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
activeDroneProfileId: activeDroneProfileId.present
|
activeDroneProfileId: activeDroneProfileId.present
|
||||||
@@ -1714,6 +1762,9 @@ class AppSettingsTableData extends DataClass
|
|||||||
connectionWifiPort: connectionWifiPort ?? this.connectionWifiPort,
|
connectionWifiPort: connectionWifiPort ?? this.connectionWifiPort,
|
||||||
connectionWifiSsidPrefix:
|
connectionWifiSsidPrefix:
|
||||||
connectionWifiSsidPrefix ?? this.connectionWifiSsidPrefix,
|
connectionWifiSsidPrefix ?? this.connectionWifiSsidPrefix,
|
||||||
|
connectionWifiLastSsid: connectionWifiLastSsid.present
|
||||||
|
? connectionWifiLastSsid.value
|
||||||
|
: this.connectionWifiLastSsid,
|
||||||
);
|
);
|
||||||
AppSettingsTableData copyWithCompanion(AppSettingsTableCompanion data) {
|
AppSettingsTableData copyWithCompanion(AppSettingsTableCompanion data) {
|
||||||
return AppSettingsTableData(
|
return AppSettingsTableData(
|
||||||
@@ -1742,6 +1793,9 @@ class AppSettingsTableData extends DataClass
|
|||||||
connectionWifiSsidPrefix: data.connectionWifiSsidPrefix.present
|
connectionWifiSsidPrefix: data.connectionWifiSsidPrefix.present
|
||||||
? data.connectionWifiSsidPrefix.value
|
? data.connectionWifiSsidPrefix.value
|
||||||
: this.connectionWifiSsidPrefix,
|
: this.connectionWifiSsidPrefix,
|
||||||
|
connectionWifiLastSsid: data.connectionWifiLastSsid.present
|
||||||
|
? data.connectionWifiLastSsid.value
|
||||||
|
: this.connectionWifiLastSsid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1756,7 +1810,8 @@ class AppSettingsTableData extends DataClass
|
|||||||
..write('connectionType: $connectionType, ')
|
..write('connectionType: $connectionType, ')
|
||||||
..write('connectionWifiHost: $connectionWifiHost, ')
|
..write('connectionWifiHost: $connectionWifiHost, ')
|
||||||
..write('connectionWifiPort: $connectionWifiPort, ')
|
..write('connectionWifiPort: $connectionWifiPort, ')
|
||||||
..write('connectionWifiSsidPrefix: $connectionWifiSsidPrefix')
|
..write('connectionWifiSsidPrefix: $connectionWifiSsidPrefix, ')
|
||||||
|
..write('connectionWifiLastSsid: $connectionWifiLastSsid')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
@@ -1772,6 +1827,7 @@ class AppSettingsTableData extends DataClass
|
|||||||
connectionWifiHost,
|
connectionWifiHost,
|
||||||
connectionWifiPort,
|
connectionWifiPort,
|
||||||
connectionWifiSsidPrefix,
|
connectionWifiSsidPrefix,
|
||||||
|
connectionWifiLastSsid,
|
||||||
);
|
);
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
@@ -1785,7 +1841,8 @@ class AppSettingsTableData extends DataClass
|
|||||||
other.connectionType == this.connectionType &&
|
other.connectionType == this.connectionType &&
|
||||||
other.connectionWifiHost == this.connectionWifiHost &&
|
other.connectionWifiHost == this.connectionWifiHost &&
|
||||||
other.connectionWifiPort == this.connectionWifiPort &&
|
other.connectionWifiPort == this.connectionWifiPort &&
|
||||||
other.connectionWifiSsidPrefix == this.connectionWifiSsidPrefix);
|
other.connectionWifiSsidPrefix == this.connectionWifiSsidPrefix &&
|
||||||
|
other.connectionWifiLastSsid == this.connectionWifiLastSsid);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppSettingsTableCompanion extends UpdateCompanion<AppSettingsTableData> {
|
class AppSettingsTableCompanion extends UpdateCompanion<AppSettingsTableData> {
|
||||||
@@ -1798,6 +1855,7 @@ class AppSettingsTableCompanion extends UpdateCompanion<AppSettingsTableData> {
|
|||||||
final Value<String?> connectionWifiHost;
|
final Value<String?> connectionWifiHost;
|
||||||
final Value<int> connectionWifiPort;
|
final Value<int> connectionWifiPort;
|
||||||
final Value<String> connectionWifiSsidPrefix;
|
final Value<String> connectionWifiSsidPrefix;
|
||||||
|
final Value<String?> connectionWifiLastSsid;
|
||||||
const AppSettingsTableCompanion({
|
const AppSettingsTableCompanion({
|
||||||
this.id = const Value.absent(),
|
this.id = const Value.absent(),
|
||||||
this.activeDroneProfileId = const Value.absent(),
|
this.activeDroneProfileId = const Value.absent(),
|
||||||
@@ -1808,6 +1866,7 @@ class AppSettingsTableCompanion extends UpdateCompanion<AppSettingsTableData> {
|
|||||||
this.connectionWifiHost = const Value.absent(),
|
this.connectionWifiHost = const Value.absent(),
|
||||||
this.connectionWifiPort = const Value.absent(),
|
this.connectionWifiPort = const Value.absent(),
|
||||||
this.connectionWifiSsidPrefix = const Value.absent(),
|
this.connectionWifiSsidPrefix = const Value.absent(),
|
||||||
|
this.connectionWifiLastSsid = const Value.absent(),
|
||||||
});
|
});
|
||||||
AppSettingsTableCompanion.insert({
|
AppSettingsTableCompanion.insert({
|
||||||
this.id = const Value.absent(),
|
this.id = const Value.absent(),
|
||||||
@@ -1819,6 +1878,7 @@ class AppSettingsTableCompanion extends UpdateCompanion<AppSettingsTableData> {
|
|||||||
this.connectionWifiHost = const Value.absent(),
|
this.connectionWifiHost = const Value.absent(),
|
||||||
this.connectionWifiPort = const Value.absent(),
|
this.connectionWifiPort = const Value.absent(),
|
||||||
this.connectionWifiSsidPrefix = const Value.absent(),
|
this.connectionWifiSsidPrefix = const Value.absent(),
|
||||||
|
this.connectionWifiLastSsid = const Value.absent(),
|
||||||
});
|
});
|
||||||
static Insertable<AppSettingsTableData> custom({
|
static Insertable<AppSettingsTableData> custom({
|
||||||
Expression<int>? id,
|
Expression<int>? id,
|
||||||
@@ -1830,6 +1890,7 @@ class AppSettingsTableCompanion extends UpdateCompanion<AppSettingsTableData> {
|
|||||||
Expression<String>? connectionWifiHost,
|
Expression<String>? connectionWifiHost,
|
||||||
Expression<int>? connectionWifiPort,
|
Expression<int>? connectionWifiPort,
|
||||||
Expression<String>? connectionWifiSsidPrefix,
|
Expression<String>? connectionWifiSsidPrefix,
|
||||||
|
Expression<String>? connectionWifiLastSsid,
|
||||||
}) {
|
}) {
|
||||||
return RawValuesInsertable({
|
return RawValuesInsertable({
|
||||||
if (id != null) 'id': id,
|
if (id != null) 'id': id,
|
||||||
@@ -1847,6 +1908,8 @@ class AppSettingsTableCompanion extends UpdateCompanion<AppSettingsTableData> {
|
|||||||
'connection_wifi_port': connectionWifiPort,
|
'connection_wifi_port': connectionWifiPort,
|
||||||
if (connectionWifiSsidPrefix != null)
|
if (connectionWifiSsidPrefix != null)
|
||||||
'connection_wifi_ssid_prefix': connectionWifiSsidPrefix,
|
'connection_wifi_ssid_prefix': connectionWifiSsidPrefix,
|
||||||
|
if (connectionWifiLastSsid != null)
|
||||||
|
'connection_wifi_last_ssid': connectionWifiLastSsid,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1860,6 +1923,7 @@ class AppSettingsTableCompanion extends UpdateCompanion<AppSettingsTableData> {
|
|||||||
Value<String?>? connectionWifiHost,
|
Value<String?>? connectionWifiHost,
|
||||||
Value<int>? connectionWifiPort,
|
Value<int>? connectionWifiPort,
|
||||||
Value<String>? connectionWifiSsidPrefix,
|
Value<String>? connectionWifiSsidPrefix,
|
||||||
|
Value<String?>? connectionWifiLastSsid,
|
||||||
}) {
|
}) {
|
||||||
return AppSettingsTableCompanion(
|
return AppSettingsTableCompanion(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
@@ -1874,6 +1938,8 @@ class AppSettingsTableCompanion extends UpdateCompanion<AppSettingsTableData> {
|
|||||||
connectionWifiPort: connectionWifiPort ?? this.connectionWifiPort,
|
connectionWifiPort: connectionWifiPort ?? this.connectionWifiPort,
|
||||||
connectionWifiSsidPrefix:
|
connectionWifiSsidPrefix:
|
||||||
connectionWifiSsidPrefix ?? this.connectionWifiSsidPrefix,
|
connectionWifiSsidPrefix ?? this.connectionWifiSsidPrefix,
|
||||||
|
connectionWifiLastSsid:
|
||||||
|
connectionWifiLastSsid ?? this.connectionWifiLastSsid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1915,6 +1981,11 @@ class AppSettingsTableCompanion extends UpdateCompanion<AppSettingsTableData> {
|
|||||||
connectionWifiSsidPrefix.value,
|
connectionWifiSsidPrefix.value,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (connectionWifiLastSsid.present) {
|
||||||
|
map['connection_wifi_last_ssid'] = Variable<String>(
|
||||||
|
connectionWifiLastSsid.value,
|
||||||
|
);
|
||||||
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1929,7 +2000,8 @@ class AppSettingsTableCompanion extends UpdateCompanion<AppSettingsTableData> {
|
|||||||
..write('connectionType: $connectionType, ')
|
..write('connectionType: $connectionType, ')
|
||||||
..write('connectionWifiHost: $connectionWifiHost, ')
|
..write('connectionWifiHost: $connectionWifiHost, ')
|
||||||
..write('connectionWifiPort: $connectionWifiPort, ')
|
..write('connectionWifiPort: $connectionWifiPort, ')
|
||||||
..write('connectionWifiSsidPrefix: $connectionWifiSsidPrefix')
|
..write('connectionWifiSsidPrefix: $connectionWifiSsidPrefix, ')
|
||||||
|
..write('connectionWifiLastSsid: $connectionWifiLastSsid')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
@@ -2574,6 +2646,7 @@ typedef $$AppSettingsTableTableCreateCompanionBuilder =
|
|||||||
Value<String?> connectionWifiHost,
|
Value<String?> connectionWifiHost,
|
||||||
Value<int> connectionWifiPort,
|
Value<int> connectionWifiPort,
|
||||||
Value<String> connectionWifiSsidPrefix,
|
Value<String> connectionWifiSsidPrefix,
|
||||||
|
Value<String?> connectionWifiLastSsid,
|
||||||
});
|
});
|
||||||
typedef $$AppSettingsTableTableUpdateCompanionBuilder =
|
typedef $$AppSettingsTableTableUpdateCompanionBuilder =
|
||||||
AppSettingsTableCompanion Function({
|
AppSettingsTableCompanion Function({
|
||||||
@@ -2586,6 +2659,7 @@ typedef $$AppSettingsTableTableUpdateCompanionBuilder =
|
|||||||
Value<String?> connectionWifiHost,
|
Value<String?> connectionWifiHost,
|
||||||
Value<int> connectionWifiPort,
|
Value<int> connectionWifiPort,
|
||||||
Value<String> connectionWifiSsidPrefix,
|
Value<String> connectionWifiSsidPrefix,
|
||||||
|
Value<String?> connectionWifiLastSsid,
|
||||||
});
|
});
|
||||||
|
|
||||||
class $$AppSettingsTableTableFilterComposer
|
class $$AppSettingsTableTableFilterComposer
|
||||||
@@ -2641,6 +2715,11 @@ class $$AppSettingsTableTableFilterComposer
|
|||||||
column: $table.connectionWifiSsidPrefix,
|
column: $table.connectionWifiSsidPrefix,
|
||||||
builder: (column) => ColumnFilters(column),
|
builder: (column) => ColumnFilters(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ColumnFilters<String> get connectionWifiLastSsid => $composableBuilder(
|
||||||
|
column: $table.connectionWifiLastSsid,
|
||||||
|
builder: (column) => ColumnFilters(column),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class $$AppSettingsTableTableOrderingComposer
|
class $$AppSettingsTableTableOrderingComposer
|
||||||
@@ -2696,6 +2775,11 @@ class $$AppSettingsTableTableOrderingComposer
|
|||||||
column: $table.connectionWifiSsidPrefix,
|
column: $table.connectionWifiSsidPrefix,
|
||||||
builder: (column) => ColumnOrderings(column),
|
builder: (column) => ColumnOrderings(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ColumnOrderings<String> get connectionWifiLastSsid => $composableBuilder(
|
||||||
|
column: $table.connectionWifiLastSsid,
|
||||||
|
builder: (column) => ColumnOrderings(column),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class $$AppSettingsTableTableAnnotationComposer
|
class $$AppSettingsTableTableAnnotationComposer
|
||||||
@@ -2749,6 +2833,11 @@ class $$AppSettingsTableTableAnnotationComposer
|
|||||||
column: $table.connectionWifiSsidPrefix,
|
column: $table.connectionWifiSsidPrefix,
|
||||||
builder: (column) => column,
|
builder: (column) => column,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
GeneratedColumn<String> get connectionWifiLastSsid => $composableBuilder(
|
||||||
|
column: $table.connectionWifiLastSsid,
|
||||||
|
builder: (column) => column,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class $$AppSettingsTableTableTableManager
|
class $$AppSettingsTableTableTableManager
|
||||||
@@ -2797,6 +2886,7 @@ class $$AppSettingsTableTableTableManager
|
|||||||
Value<String?> connectionWifiHost = const Value.absent(),
|
Value<String?> connectionWifiHost = const Value.absent(),
|
||||||
Value<int> connectionWifiPort = const Value.absent(),
|
Value<int> connectionWifiPort = const Value.absent(),
|
||||||
Value<String> connectionWifiSsidPrefix = const Value.absent(),
|
Value<String> connectionWifiSsidPrefix = const Value.absent(),
|
||||||
|
Value<String?> connectionWifiLastSsid = const Value.absent(),
|
||||||
}) => AppSettingsTableCompanion(
|
}) => AppSettingsTableCompanion(
|
||||||
id: id,
|
id: id,
|
||||||
activeDroneProfileId: activeDroneProfileId,
|
activeDroneProfileId: activeDroneProfileId,
|
||||||
@@ -2807,6 +2897,7 @@ class $$AppSettingsTableTableTableManager
|
|||||||
connectionWifiHost: connectionWifiHost,
|
connectionWifiHost: connectionWifiHost,
|
||||||
connectionWifiPort: connectionWifiPort,
|
connectionWifiPort: connectionWifiPort,
|
||||||
connectionWifiSsidPrefix: connectionWifiSsidPrefix,
|
connectionWifiSsidPrefix: connectionWifiSsidPrefix,
|
||||||
|
connectionWifiLastSsid: connectionWifiLastSsid,
|
||||||
),
|
),
|
||||||
createCompanionCallback:
|
createCompanionCallback:
|
||||||
({
|
({
|
||||||
@@ -2819,6 +2910,7 @@ class $$AppSettingsTableTableTableManager
|
|||||||
Value<String?> connectionWifiHost = const Value.absent(),
|
Value<String?> connectionWifiHost = const Value.absent(),
|
||||||
Value<int> connectionWifiPort = const Value.absent(),
|
Value<int> connectionWifiPort = const Value.absent(),
|
||||||
Value<String> connectionWifiSsidPrefix = const Value.absent(),
|
Value<String> connectionWifiSsidPrefix = const Value.absent(),
|
||||||
|
Value<String?> connectionWifiLastSsid = const Value.absent(),
|
||||||
}) => AppSettingsTableCompanion.insert(
|
}) => AppSettingsTableCompanion.insert(
|
||||||
id: id,
|
id: id,
|
||||||
activeDroneProfileId: activeDroneProfileId,
|
activeDroneProfileId: activeDroneProfileId,
|
||||||
@@ -2829,6 +2921,7 @@ class $$AppSettingsTableTableTableManager
|
|||||||
connectionWifiHost: connectionWifiHost,
|
connectionWifiHost: connectionWifiHost,
|
||||||
connectionWifiPort: connectionWifiPort,
|
connectionWifiPort: connectionWifiPort,
|
||||||
connectionWifiSsidPrefix: connectionWifiSsidPrefix,
|
connectionWifiSsidPrefix: connectionWifiSsidPrefix,
|
||||||
|
connectionWifiLastSsid: connectionWifiLastSsid,
|
||||||
),
|
),
|
||||||
withReferenceMapper: (p0) => p0
|
withReferenceMapper: (p0) => p0
|
||||||
.map((e) => (e.readTable(table), BaseReferences(db, table, e)))
|
.map((e) => (e.readTable(table), BaseReferences(db, table, e)))
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class AppSettingsRepository {
|
|||||||
String? connectionWifiHost,
|
String? connectionWifiHost,
|
||||||
int connectionWifiPort,
|
int connectionWifiPort,
|
||||||
String connectionWifiSsidPrefix,
|
String connectionWifiSsidPrefix,
|
||||||
|
String? connectionWifiLastSsid,
|
||||||
})> load() async {
|
})> load() async {
|
||||||
final row = await (_db.select(_db.appSettingsTable)
|
final row = await (_db.select(_db.appSettingsTable)
|
||||||
..where((s) => s.id.equals(_rowId)))
|
..where((s) => s.id.equals(_rowId)))
|
||||||
@@ -40,6 +41,7 @@ class AppSettingsRepository {
|
|||||||
connectionWifiPort: row?.connectionWifiPort ?? kDefaultWifiPort,
|
connectionWifiPort: row?.connectionWifiPort ?? kDefaultWifiPort,
|
||||||
connectionWifiSsidPrefix:
|
connectionWifiSsidPrefix:
|
||||||
row?.connectionWifiSsidPrefix ?? kDefaultWifiSsidPrefix,
|
row?.connectionWifiSsidPrefix ?? kDefaultWifiSsidPrefix,
|
||||||
|
connectionWifiLastSsid: row?.connectionWifiLastSsid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +121,18 @@ class AppSettingsRepository {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Exakte SSID der zuletzt erfolgreich verbundenen mLRS-Bruecke (Doku
|
||||||
|
/// Abschnitt 8), oder null solange noch nie erfolgreich verbunden wurde.
|
||||||
|
Future<String?> loadConnectionWifiLastSsid() async =>
|
||||||
|
(await load()).connectionWifiLastSsid;
|
||||||
|
|
||||||
|
Future<void> setConnectionWifiLastSsid(String? ssid) async {
|
||||||
|
await _upsert(AppSettingsTableCompanion(
|
||||||
|
id: const Value(_rowId),
|
||||||
|
connectionWifiLastSsid: Value(ssid),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _upsert(AppSettingsTableCompanion companion) async {
|
Future<void> _upsert(AppSettingsTableCompanion companion) async {
|
||||||
await _db.into(_db.appSettingsTable).insertOnConflictUpdate(companion);
|
await _db.into(_db.appSettingsTable).insertOnConflictUpdate(companion);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,19 @@ sealed class MlrsNetworkEvent {
|
|||||||
const MlrsNetworkEvent();
|
const MlrsNetworkEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Das Netz ist verfuegbar (Nutzer hat den Systemdialog bestaetigt).
|
/// Das Netz ist verfuegbar (Nutzer hat den Systemdialog bestaetigt, oder
|
||||||
|
/// Android hat eine zuvor bewilligte exakte SSID still erneut verbunden).
|
||||||
/// [gatewayAddress] ist die Gateway-Adresse des Netzes, falls ermittelbar -
|
/// [gatewayAddress] ist die Gateway-Adresse des Netzes, falls ermittelbar -
|
||||||
/// dient als Vorbelegung der Zieladresse, bevor eine Gegenstelle aus dem
|
/// dient als Vorbelegung der Zieladresse, bevor eine Gegenstelle aus dem
|
||||||
/// Verkehr gelernt wurde (Doku Abschnitt 3).
|
/// Verkehr gelernt wurde (Doku Abschnitt 3). [ssid] ist die tatsaechliche
|
||||||
|
/// SSID des verbundenen Netzes, falls ermittelbar - wird gemerkt, damit
|
||||||
|
/// kuenftige Verbindungen exakt (statt per Praefix) angefragt werden koennen
|
||||||
|
/// (siehe [MlrsNetworkController.requestNetwork]).
|
||||||
class MlrsNetworkAvailable extends MlrsNetworkEvent {
|
class MlrsNetworkAvailable extends MlrsNetworkEvent {
|
||||||
const MlrsNetworkAvailable({this.gatewayAddress});
|
const MlrsNetworkAvailable({this.gatewayAddress, this.ssid});
|
||||||
|
|
||||||
final String? gatewayAddress;
|
final String? gatewayAddress;
|
||||||
|
final String? ssid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Die Anfrage konnte nicht erfuellt werden (Nutzer hat den Systemdialog
|
/// Die Anfrage konnte nicht erfuellt werden (Nutzer hat den Systemdialog
|
||||||
@@ -79,9 +84,13 @@ abstract class MlrsNetworkController {
|
|||||||
Stream<MlrsNetworkEvent> get events;
|
Stream<MlrsNetworkEvent> get events;
|
||||||
|
|
||||||
/// Loest `ConnectivityManager.requestNetwork()` mit einem
|
/// Loest `ConnectivityManager.requestNetwork()` mit einem
|
||||||
/// `WifiNetworkSpecifier` aus, dessen SSID-Muster auf [ssidPrefix] passt.
|
/// `WifiNetworkSpecifier` aus. Ist [preferredSsid] gesetzt (zuvor
|
||||||
|
/// erfolgreich verbundene, gemerkte SSID), wird exakt danach gefragt -
|
||||||
|
/// Android kann das dann ohne erneuten Systemdialog automatisch bewilligen
|
||||||
|
/// (Doku Abschnitt 8: "Verbindung automatisch herstellen"). Sonst wird
|
||||||
|
/// [ssidPrefix] als Praefix-Muster verwendet (zeigt immer den Dialog).
|
||||||
/// Das Ergebnis kommt asynchron ueber [events] (available/unavailable).
|
/// Das Ergebnis kommt asynchron ueber [events] (available/unavailable).
|
||||||
Future<void> requestNetwork(String ssidPrefix);
|
Future<void> requestNetwork(String ssidPrefix, {String? preferredSsid});
|
||||||
|
|
||||||
/// Meldet den Callback ab und geht damit von der aktuellen Anfrage
|
/// Meldet den Callback ab und geht damit von der aktuellen Anfrage
|
||||||
/// zurueck - keine weiteren [events] danach, bis erneut angefragt wird.
|
/// zurueck - keine weiteren [events] danach, bis erneut angefragt wird.
|
||||||
@@ -139,6 +148,7 @@ class MethodChannelMlrsNetworkController implements MlrsNetworkController {
|
|||||||
return switch (map['type']) {
|
return switch (map['type']) {
|
||||||
'available' => MlrsNetworkAvailable(
|
'available' => MlrsNetworkAvailable(
|
||||||
gatewayAddress: map['gatewayAddress'] as String?,
|
gatewayAddress: map['gatewayAddress'] as String?,
|
||||||
|
ssid: map['ssid'] as String?,
|
||||||
),
|
),
|
||||||
'lost' => const MlrsNetworkLost(),
|
'lost' => const MlrsNetworkLost(),
|
||||||
_ => const MlrsNetworkUnavailable(),
|
_ => const MlrsNetworkUnavailable(),
|
||||||
@@ -155,8 +165,11 @@ class MethodChannelMlrsNetworkController implements MlrsNetworkController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> requestNetwork(String ssidPrefix) => _methodChannel
|
Future<void> requestNetwork(String ssidPrefix, {String? preferredSsid}) =>
|
||||||
.invokeMethod('requestNetwork', {'ssidPrefix': ssidPrefix});
|
_methodChannel.invokeMethod('requestNetwork', {
|
||||||
|
'ssidPrefix': ssidPrefix,
|
||||||
|
'exactSsid': preferredSsid,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> releaseNetwork() => _methodChannel.invokeMethod('releaseNetwork');
|
Future<void> releaseNetwork() => _methodChannel.invokeMethod('releaseNetwork');
|
||||||
|
|||||||
@@ -32,16 +32,22 @@ class UdpTransport implements LinkTransport {
|
|||||||
required Future<String?> Function() getHost,
|
required Future<String?> Function() getHost,
|
||||||
required Future<int> Function() getPort,
|
required Future<int> Function() getPort,
|
||||||
required Future<String> Function() getSsidPrefix,
|
required Future<String> Function() getSsidPrefix,
|
||||||
|
required Future<String?> Function() getRememberedSsid,
|
||||||
|
required Future<void> Function(String ssid) rememberSsid,
|
||||||
MlrsNetworkController? networkController,
|
MlrsNetworkController? networkController,
|
||||||
}) : _getHost = getHost,
|
}) : _getHost = getHost,
|
||||||
_getPort = getPort,
|
_getPort = getPort,
|
||||||
_getSsidPrefix = getSsidPrefix,
|
_getSsidPrefix = getSsidPrefix,
|
||||||
|
_getRememberedSsid = getRememberedSsid,
|
||||||
|
_rememberSsid = rememberSsid,
|
||||||
_networkController =
|
_networkController =
|
||||||
networkController ?? MethodChannelMlrsNetworkController();
|
networkController ?? MethodChannelMlrsNetworkController();
|
||||||
|
|
||||||
final Future<String?> Function() _getHost;
|
final Future<String?> Function() _getHost;
|
||||||
final Future<int> Function() _getPort;
|
final Future<int> Function() _getPort;
|
||||||
final Future<String> Function() _getSsidPrefix;
|
final Future<String> Function() _getSsidPrefix;
|
||||||
|
final Future<String?> Function() _getRememberedSsid;
|
||||||
|
final Future<void> Function(String ssid) _rememberSsid;
|
||||||
final MlrsNetworkController _networkController;
|
final MlrsNetworkController _networkController;
|
||||||
|
|
||||||
final _incomingController = StreamController<Uint8List>.broadcast();
|
final _incomingController = StreamController<Uint8List>.broadcast();
|
||||||
@@ -54,6 +60,7 @@ class UdpTransport implements LinkTransport {
|
|||||||
int? _boundPort;
|
int? _boundPort;
|
||||||
bool _socketOpen = false;
|
bool _socketOpen = false;
|
||||||
bool? _staConcurrencySupported;
|
bool? _staConcurrencySupported;
|
||||||
|
String? _connectedSsid;
|
||||||
|
|
||||||
LinkState _state = LinkState.disconnected;
|
LinkState _state = LinkState.disconnected;
|
||||||
LinkErrorReason? _lastErrorReason;
|
LinkErrorReason? _lastErrorReason;
|
||||||
@@ -85,6 +92,13 @@ class UdpTransport implements LinkTransport {
|
|||||||
/// nicht ermittelbar (API < 30, Doku Abschnitt 4/8).
|
/// nicht ermittelbar (API < 30, Doku Abschnitt 4/8).
|
||||||
bool? get staConcurrencySupported => _staConcurrencySupported;
|
bool? get staConcurrencySupported => _staConcurrencySupported;
|
||||||
|
|
||||||
|
/// Tatsaechliche SSID des verbundenen Netzes, sobald von Android
|
||||||
|
/// ermittelbar (Doku Abschnitt 8: "verbundenes WLAN anzeigen"). Wird bei
|
||||||
|
/// jedem erfolgreichen [connect] auch dauerhaft gemerkt (siehe
|
||||||
|
/// [_rememberSsid]), damit kuenftige Verbindungen exakt statt per Praefix
|
||||||
|
/// angefragt werden koennen.
|
||||||
|
String? get connectedSsid => _connectedSsid;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> connect() async {
|
Future<void> connect() async {
|
||||||
_lastErrorReason = null;
|
_lastErrorReason = null;
|
||||||
@@ -92,13 +106,17 @@ class UdpTransport implements LinkTransport {
|
|||||||
_setState(LinkState.connecting);
|
_setState(LinkState.connecting);
|
||||||
|
|
||||||
final ssidPrefix = await _getSsidPrefix();
|
final ssidPrefix = await _getSsidPrefix();
|
||||||
|
final rememberedSsid = await _getRememberedSsid();
|
||||||
final firstEvent = Completer<MlrsNetworkEvent>();
|
final firstEvent = Completer<MlrsNetworkEvent>();
|
||||||
final requestSub = _networkController.events.listen((event) {
|
final requestSub = _networkController.events.listen((event) {
|
||||||
if (!firstEvent.isCompleted) firstEvent.complete(event);
|
if (!firstEvent.isCompleted) firstEvent.complete(event);
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await _networkController.requestNetwork(ssidPrefix);
|
await _networkController.requestNetwork(
|
||||||
|
ssidPrefix,
|
||||||
|
preferredSsid: rememberedSsid,
|
||||||
|
);
|
||||||
final event = await firstEvent.future;
|
final event = await firstEvent.future;
|
||||||
await requestSub.cancel();
|
await requestSub.cancel();
|
||||||
|
|
||||||
@@ -115,6 +133,11 @@ class UdpTransport implements LinkTransport {
|
|||||||
// unten, nicht erst danach (Doku Abschnitt 8).
|
// unten, nicht erst danach (Doku Abschnitt 8).
|
||||||
_networkLossSub = _networkController.events.listen(_onNetworkEvent);
|
_networkLossSub = _networkController.events.listen(_onNetworkEvent);
|
||||||
|
|
||||||
|
_connectedSsid = available.ssid;
|
||||||
|
if (available.ssid != null) {
|
||||||
|
await _rememberSsid(available.ssid!);
|
||||||
|
}
|
||||||
|
|
||||||
final configuredHost = await _getHost();
|
final configuredHost = await _getHost();
|
||||||
final configuredPort = await _getPort();
|
final configuredPort = await _getPort();
|
||||||
final prefillHost = (configuredHost != null && configuredHost.isNotEmpty)
|
final prefillHost = (configuredHost != null && configuredHost.isNotEmpty)
|
||||||
@@ -170,6 +193,7 @@ class UdpTransport implements LinkTransport {
|
|||||||
_packetSub?.cancel();
|
_packetSub?.cancel();
|
||||||
_packetSub = null;
|
_packetSub = null;
|
||||||
_boundPort = null;
|
_boundPort = null;
|
||||||
|
_connectedSsid = null;
|
||||||
if (_socketOpen) {
|
if (_socketOpen) {
|
||||||
_socketOpen = false;
|
_socketOpen = false;
|
||||||
unawaited(_networkController.closeSocket());
|
unawaited(_networkController.closeSocket());
|
||||||
@@ -193,6 +217,7 @@ class UdpTransport implements LinkTransport {
|
|||||||
await _packetSub?.cancel();
|
await _packetSub?.cancel();
|
||||||
_packetSub = null;
|
_packetSub = null;
|
||||||
_boundPort = null;
|
_boundPort = null;
|
||||||
|
_connectedSsid = null;
|
||||||
if (_socketOpen) {
|
if (_socketOpen) {
|
||||||
_socketOpen = false;
|
_socketOpen = false;
|
||||||
await _networkController.closeSocket();
|
await _networkController.closeSocket();
|
||||||
@@ -220,9 +245,14 @@ class UdpTransport implements LinkTransport {
|
|||||||
_packetSub?.cancel();
|
_packetSub?.cancel();
|
||||||
if (_socketOpen) {
|
if (_socketOpen) {
|
||||||
_socketOpen = false;
|
_socketOpen = false;
|
||||||
unawaited(_networkController.closeSocket());
|
// dispose() darf nie eine unbehandelte Future-Exception hinterlassen -
|
||||||
|
// z.B. wirft der Platform-Channel MissingPluginException, wenn
|
||||||
|
// ueberhaupt kein natives Gegenstueck existiert (Tests, Web/Desktop-
|
||||||
|
// UI-Vorschau). Der Aufrufer kann an dieser Stelle ohnehin nicht mehr
|
||||||
|
// reagieren.
|
||||||
|
unawaited(_networkController.closeSocket().catchError((_) {}));
|
||||||
}
|
}
|
||||||
unawaited(_networkController.releaseNetwork());
|
unawaited(_networkController.releaseNetwork().catchError((_) {}));
|
||||||
_networkController.dispose();
|
_networkController.dispose();
|
||||||
_incomingController.close();
|
_incomingController.close();
|
||||||
_stateController.close();
|
_stateController.close();
|
||||||
|
|||||||
@@ -9,6 +9,6 @@ abstract final class DmcColors {
|
|||||||
static const liveGreen = Color(0xFF3ECF8E);
|
static const liveGreen = Color(0xFF3ECF8E);
|
||||||
static const warnRed = Color(0xFFE2574A);
|
static const warnRed = Color(0xFFE2574A);
|
||||||
static const pafAmber = Color(0xFFF0C86E);
|
static const pafAmber = Color(0xFFF0C86E);
|
||||||
static const editModeGreen = Color(0xFF50C878);
|
static const planModeColor = Color(0xFFE2574A);
|
||||||
static const flyModeRed = Color(0xFFE2574A);
|
static const flyModeColor = Color(0xFF50C878);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ final wifiTransportProvider = Provider<UdpTransport>((ref) {
|
|||||||
getHost: settingsRepo.loadConnectionWifiHost,
|
getHost: settingsRepo.loadConnectionWifiHost,
|
||||||
getPort: settingsRepo.loadConnectionWifiPort,
|
getPort: settingsRepo.loadConnectionWifiPort,
|
||||||
getSsidPrefix: settingsRepo.loadConnectionWifiSsidPrefix,
|
getSsidPrefix: settingsRepo.loadConnectionWifiSsidPrefix,
|
||||||
|
getRememberedSsid: settingsRepo.loadConnectionWifiLastSsid,
|
||||||
|
rememberSsid: settingsRepo.setConnectionWifiLastSsid,
|
||||||
);
|
);
|
||||||
ref.onDispose(transport.dispose);
|
ref.onDispose(transport.dispose);
|
||||||
return transport;
|
return transport;
|
||||||
@@ -134,9 +136,10 @@ class WifiConnectionLogNotifier
|
|||||||
final message = switch (linkState) {
|
final message = switch (linkState) {
|
||||||
LinkState.disconnected => 'Disconnected',
|
LinkState.disconnected => 'Disconnected',
|
||||||
LinkState.connecting => 'Requesting mLRS network...',
|
LinkState.connecting => 'Requesting mLRS network...',
|
||||||
LinkState.connected =>
|
LinkState.connected => 'Connected to '
|
||||||
'Network available, listening on port ${transport.boundPort}'
|
'${transport.connectedSsid ?? 'network'}, listening on port '
|
||||||
' (STA concurrency: ${_formatStaConcurrency(transport.staConcurrencySupported)})',
|
'${transport.boundPort} (STA concurrency: '
|
||||||
|
'${_formatStaConcurrency(transport.staConcurrencySupported)})',
|
||||||
LinkState.error => 'Error: '
|
LinkState.error => 'Error: '
|
||||||
'${transport.lastErrorMessage ?? transport.lastErrorReason?.name ?? 'unknown'}',
|
'${transport.lastErrorMessage ?? transport.lastErrorReason?.name ?? 'unknown'}',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -150,6 +150,12 @@ class _WifiPanelState extends ConsumerState<_WifiPanel> {
|
|||||||
final connectionSettings = ref.watch(connectionSettingsProvider).value;
|
final connectionSettings = ref.watch(connectionSettingsProvider).value;
|
||||||
final log = ref.watch(wifiConnectionLogProvider);
|
final log = ref.watch(wifiConnectionLogProvider);
|
||||||
final packetCount = ref.watch(wifiConnectionLogProvider.notifier).packetCount;
|
final packetCount = ref.watch(wifiConnectionLogProvider.notifier).packetCount;
|
||||||
|
// Kein eigener Reaktivitaets-Provider fuer connectedSsid noetig - der
|
||||||
|
// Rebuild wird bereits durch das Beobachten von wifiLinkStateProvider
|
||||||
|
// oben ausgeloest, und das Feld wird synchron gesetzt, bevor der
|
||||||
|
// Transport auf LinkState.connected wechselt (siehe UdpTransport.connect).
|
||||||
|
final connectedSsid = ref.read(wifiTransportProvider).connectedSsid;
|
||||||
|
final rememberedSsid = connectionSettings?.connectionWifiLastSsid;
|
||||||
|
|
||||||
// Controller einmalig aus den gespeicherten Einstellungen befuellen -
|
// Controller einmalig aus den gespeicherten Einstellungen befuellen -
|
||||||
// nicht bei jedem Rebuild, sonst wird waehrend der Nutzereingabe
|
// nicht bei jedem Rebuild, sonst wird waehrend der Nutzereingabe
|
||||||
@@ -188,6 +194,23 @@ class _WifiPanelState extends ConsumerState<_WifiPanel> {
|
|||||||
'break maps/weather.',
|
'break maps/weather.',
|
||||||
style: TextStyle(fontSize: 12, color: Colors.grey),
|
style: TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
if (connectedSsid != null)
|
||||||
|
Text(
|
||||||
|
'Connected to: $connectedSsid',
|
||||||
|
style: const TextStyle(fontSize: 12, color: DmcColors.liveGreen),
|
||||||
|
)
|
||||||
|
else if (rememberedSsid != null)
|
||||||
|
Text(
|
||||||
|
'Remembered network: $rememberedSsid',
|
||||||
|
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
const Text(
|
||||||
|
'No network remembered yet - connect once to remember it for '
|
||||||
|
'automatic reconnection.',
|
||||||
|
style: TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
|
),
|
||||||
if (errorReason != null) ...[
|
if (errorReason != null) ...[
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
_WifiErrorHint(reason: errorReason),
|
_WifiErrorHint(reason: errorReason),
|
||||||
@@ -253,6 +276,22 @@ class _WifiPanelState extends ConsumerState<_WifiPanel> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
SwitchListTile(
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
title: const Text('Auto-connect when entering Fly mode'),
|
||||||
|
subtitle: const Text(
|
||||||
|
'Only once a network has been remembered (see above).',
|
||||||
|
style: TextStyle(fontSize: 11),
|
||||||
|
),
|
||||||
|
value: connectionSettings?.connectionAutoConnect ?? true,
|
||||||
|
onChanged: (value) async {
|
||||||
|
await ref
|
||||||
|
.read(appSettingsRepositoryProvider)
|
||||||
|
.setConnectionAutoConnect(value);
|
||||||
|
ref.invalidate(connectionSettingsProvider);
|
||||||
|
},
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
'Connection log ($packetCount packets received)',
|
'Connection log ($packetCount packets received)',
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'dart:async';
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -5,8 +6,12 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../../app_mode/app_mode_cubit.dart';
|
import '../../app_mode/app_mode_cubit.dart';
|
||||||
|
import '../../transport/connection_type.dart';
|
||||||
|
import '../../transport/link_transport.dart';
|
||||||
import '../dmc_colors.dart';
|
import '../dmc_colors.dart';
|
||||||
|
import '../providers/connection_settings_provider.dart';
|
||||||
import '../providers/flight_mode_provider.dart';
|
import '../providers/flight_mode_provider.dart';
|
||||||
|
import '../providers/wifi_connection_provider.dart';
|
||||||
import 'flight_mode_pill.dart';
|
import 'flight_mode_pill.dart';
|
||||||
import 'fly_map_controls.dart';
|
import 'fly_map_controls.dart';
|
||||||
import 'header_wind_pill.dart';
|
import 'header_wind_pill.dart';
|
||||||
@@ -35,7 +40,7 @@ class TopModeBar extends ConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final isFly = context.select((AppModeCubit c) => c.state.mode == AppMode.fly);
|
final isFly = context.select((AppModeCubit c) => c.state.mode == AppMode.fly);
|
||||||
final activeTint = isFly ? DmcColors.flyModeRed : DmcColors.editModeGreen;
|
final activeTint = isFly ? DmcColors.flyModeColor : DmcColors.planModeColor;
|
||||||
|
|
||||||
// Kein SafeArea: das wendet links/rechts die jeweils tatsaechlichen
|
// Kein SafeArea: das wendet links/rechts die jeweils tatsaechlichen
|
||||||
// (oft asymmetrischen) Insets an, wodurch die Leiste sichtbar von der
|
// (oft asymmetrischen) Insets an, wodurch die Leiste sichtbar von der
|
||||||
@@ -72,7 +77,7 @@ class TopModeBar extends ConsumerWidget {
|
|||||||
_ModeButton(
|
_ModeButton(
|
||||||
label: 'Plan',
|
label: 'Plan',
|
||||||
isActive: !isFly,
|
isActive: !isFly,
|
||||||
inactiveColor: DmcColors.editModeGreen,
|
inactiveColor: DmcColors.planModeColor,
|
||||||
cornerRadius: const BorderRadius.only(
|
cornerRadius: const BorderRadius.only(
|
||||||
bottomLeft: Radius.circular(26),
|
bottomLeft: Radius.circular(26),
|
||||||
),
|
),
|
||||||
@@ -82,6 +87,8 @@ class TopModeBar extends ConsumerWidget {
|
|||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
const HeaderWindPill(),
|
const HeaderWindPill(),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
|
const _WifiConnectionProgressPill(),
|
||||||
|
const SizedBox(width: 8),
|
||||||
const Expanded(child: FlightModePill()),
|
const Expanded(child: FlightModePill()),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
const FlyMapControls(),
|
const FlyMapControls(),
|
||||||
@@ -96,7 +103,7 @@ class TopModeBar extends ConsumerWidget {
|
|||||||
_ModeButton(
|
_ModeButton(
|
||||||
label: 'Fly',
|
label: 'Fly',
|
||||||
isActive: isFly,
|
isActive: isFly,
|
||||||
inactiveColor: DmcColors.flyModeRed,
|
inactiveColor: DmcColors.flyModeColor,
|
||||||
cornerRadius: const BorderRadius.only(
|
cornerRadius: const BorderRadius.only(
|
||||||
bottomRight: Radius.circular(26),
|
bottomRight: Radius.circular(26),
|
||||||
),
|
),
|
||||||
@@ -105,6 +112,7 @@ class TopModeBar extends ConsumerWidget {
|
|||||||
// Eintritt in den Fly-Modus setzt immer auf Waypoint
|
// Eintritt in den Fly-Modus setzt immer auf Waypoint
|
||||||
// zurueck (Doku 3.11).
|
// zurueck (Doku 3.11).
|
||||||
ref.read(flightModeProvider.notifier).reset();
|
ref.read(flightModeProvider.notifier).reset();
|
||||||
|
_maybeAutoConnectWifi(ref);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -115,6 +123,86 @@ class TopModeBar extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Verbindet automatisch zur mLRS-Bruecke, wenn in den Fly-Modus gewechselt
|
||||||
|
/// wird (Doku Kommunikationsschicht v2 Abschnitt 8: "Verbindung automatisch
|
||||||
|
/// herstellen bei Wechsel in Fly, wenn WLAN gemerkt"). Voraussetzungen:
|
||||||
|
/// Verbindungsart ist WLAN, "Auto-connect"-Einstellung ist an, und es gibt
|
||||||
|
/// bereits eine gemerkte SSID aus einer frueheren erfolgreichen Verbindung -
|
||||||
|
/// ohne gemerkte SSID muesste ohnehin der Systemdialog erscheinen, das ist
|
||||||
|
/// dann kein "automatisches" Verbinden mehr. Der Fortschritt ist ueber
|
||||||
|
/// [_WifiConnectionProgressPill] sichtbar.
|
||||||
|
Future<void> _maybeAutoConnectWifi(WidgetRef ref) async {
|
||||||
|
final settings = ref.read(connectionSettingsProvider).value;
|
||||||
|
if (settings == null) return;
|
||||||
|
if (settings.connectionType != ConnectionType.wifi) return;
|
||||||
|
if (!settings.connectionAutoConnect) return;
|
||||||
|
if (settings.connectionWifiLastSsid == null) return;
|
||||||
|
|
||||||
|
final transport = ref.read(wifiTransportProvider);
|
||||||
|
if (transport.currentState == LinkState.connected ||
|
||||||
|
transport.currentState == LinkState.connecting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await transport.connect();
|
||||||
|
} on LinkConnectException {
|
||||||
|
// Grund/Nachricht sind bereits ueber den State-Stream gemeldet, siehe
|
||||||
|
// _WifiConnectionProgressPill.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Kompakte Fortschrittsanzeige fuer den automatischen WLAN-Verbindungsaufbau
|
||||||
|
/// (siehe [_maybeAutoConnectWifi]) - nur sichtbar, solange die Verbindungsart
|
||||||
|
/// WLAN ist und gerade etwas passiert bzw. ein Fehler vorliegt. Bleibt im
|
||||||
|
/// Ruhezustand (disconnected, kein vorheriger Fehler) unsichtbar, damit die
|
||||||
|
/// Kopfleiste nicht dauerhaft mit einer Statuspille zugestellt ist.
|
||||||
|
class _WifiConnectionProgressPill extends ConsumerWidget {
|
||||||
|
const _WifiConnectionProgressPill();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final connectionType = ref.watch(connectionSettingsProvider).value?.connectionType;
|
||||||
|
final linkState = ref.watch(wifiLinkStateProvider).value;
|
||||||
|
if (connectionType != ConnectionType.wifi) return const SizedBox.shrink();
|
||||||
|
if (linkState == null || linkState == LinkState.disconnected) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
|
||||||
|
final (label, color) = switch (linkState) {
|
||||||
|
LinkState.connecting => ('Connecting…', DmcColors.pafAmber),
|
||||||
|
LinkState.connected => ('WiFi connected', DmcColors.liveGreen),
|
||||||
|
LinkState.error => ('WiFi error', DmcColors.warnRed),
|
||||||
|
LinkState.disconnected => ('', Colors.grey),
|
||||||
|
};
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 8),
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: color.withValues(alpha: 0.2),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(color: color),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
if (linkState == LinkState.connecting) ...[
|
||||||
|
SizedBox(
|
||||||
|
width: 10,
|
||||||
|
height: 10,
|
||||||
|
child: CircularProgressIndicator(strokeWidth: 1.5, color: color),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
],
|
||||||
|
Text(label, style: TextStyle(color: color, fontSize: 11)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _ModeButton extends StatelessWidget {
|
class _ModeButton extends StatelessWidget {
|
||||||
const _ModeButton({
|
const _ModeButton({
|
||||||
required this.label,
|
required this.label,
|
||||||
|
|||||||
@@ -117,4 +117,23 @@ void main() {
|
|||||||
|
|
||||||
expect(await repository.loadConnectionWifiSsidPrefix(), 'mLRS-1234');
|
expect(await repository.loadConnectionWifiSsidPrefix(), 'mLRS-1234');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('gemerkte SSID: Standard ist null (noch nie verbunden)', () async {
|
||||||
|
final settings = await repository.load();
|
||||||
|
expect(settings.connectionWifiLastSsid, isNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('setConnectionWifiLastSsid merkt sich die verbundene SSID', () async {
|
||||||
|
await repository.setConnectionWifiLastSsid('mLRS-ABCD');
|
||||||
|
|
||||||
|
expect(await repository.loadConnectionWifiLastSsid(), 'mLRS-ABCD');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('setConnectionWifiLastSsid(null) loescht die Erinnerung wieder',
|
||||||
|
() async {
|
||||||
|
await repository.setConnectionWifiLastSsid('mLRS-ABCD');
|
||||||
|
await repository.setConnectionWifiLastSsid(null);
|
||||||
|
|
||||||
|
expect(await repository.loadConnectionWifiLastSsid(), isNull);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ class FakeMlrsNetworkController implements MlrsNetworkController {
|
|||||||
final _packetsController = StreamController<MlrsSocketPacket>.broadcast();
|
final _packetsController = StreamController<MlrsSocketPacket>.broadcast();
|
||||||
|
|
||||||
final List<String> requestedSsidPrefixes = [];
|
final List<String> requestedSsidPrefixes = [];
|
||||||
|
final List<String?> requestedPreferredSsids = [];
|
||||||
final List<({Uint8List data, String host, int port})> sentPackets = [];
|
final List<({Uint8List data, String host, int port})> sentPackets = [];
|
||||||
|
final List<String> rememberedSsids = [];
|
||||||
int releaseCount = 0;
|
int releaseCount = 0;
|
||||||
int openSocketCount = 0;
|
int openSocketCount = 0;
|
||||||
int closeSocketCount = 0;
|
int closeSocketCount = 0;
|
||||||
@@ -38,8 +40,9 @@ class FakeMlrsNetworkController implements MlrsNetworkController {
|
|||||||
void emitPacket(MlrsSocketPacket packet) => _packetsController.add(packet);
|
void emitPacket(MlrsSocketPacket packet) => _packetsController.add(packet);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> requestNetwork(String ssidPrefix) async {
|
Future<void> requestNetwork(String ssidPrefix, {String? preferredSsid}) async {
|
||||||
requestedSsidPrefixes.add(ssidPrefix);
|
requestedSsidPrefixes.add(ssidPrefix);
|
||||||
|
requestedPreferredSsids.add(preferredSsid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -88,12 +91,15 @@ void main() {
|
|||||||
String? host,
|
String? host,
|
||||||
int port = 0,
|
int port = 0,
|
||||||
String ssidPrefix = 'mLRS-',
|
String ssidPrefix = 'mLRS-',
|
||||||
|
String? rememberedSsid,
|
||||||
MlrsNetworkEvent event = const MlrsNetworkAvailable(),
|
MlrsNetworkEvent event = const MlrsNetworkAvailable(),
|
||||||
}) async {
|
}) async {
|
||||||
final transport = UdpTransport(
|
final transport = UdpTransport(
|
||||||
getHost: () async => host,
|
getHost: () async => host,
|
||||||
getPort: () async => port,
|
getPort: () async => port,
|
||||||
getSsidPrefix: () async => ssidPrefix,
|
getSsidPrefix: () async => ssidPrefix,
|
||||||
|
getRememberedSsid: () async => rememberedSsid,
|
||||||
|
rememberSsid: (ssid) async => fake.rememberedSsids.add(ssid),
|
||||||
networkController: fake,
|
networkController: fake,
|
||||||
);
|
);
|
||||||
final connectFuture = transport.connect();
|
final connectFuture = transport.connect();
|
||||||
@@ -133,6 +139,8 @@ void main() {
|
|||||||
getHost: () async => null,
|
getHost: () async => null,
|
||||||
getPort: () async => 0,
|
getPort: () async => 0,
|
||||||
getSsidPrefix: () async => 'mLRS-',
|
getSsidPrefix: () async => 'mLRS-',
|
||||||
|
getRememberedSsid: () async => null,
|
||||||
|
rememberSsid: (_) async {},
|
||||||
networkController: fake,
|
networkController: fake,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -286,4 +294,44 @@ void main() {
|
|||||||
|
|
||||||
transport.dispose();
|
transport.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('passes the remembered SSID to requestNetwork for a silent reconnect',
|
||||||
|
() async {
|
||||||
|
final fake = FakeMlrsNetworkController();
|
||||||
|
final transport = await connectWithFake(
|
||||||
|
fake,
|
||||||
|
rememberedSsid: 'mLRS-1234',
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(fake.requestedPreferredSsids, ['mLRS-1234']);
|
||||||
|
|
||||||
|
transport.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('remembers the connected SSID reported by the platform', () async {
|
||||||
|
final fake = FakeMlrsNetworkController();
|
||||||
|
final transport = await connectWithFake(
|
||||||
|
fake,
|
||||||
|
event: const MlrsNetworkAvailable(ssid: 'mLRS-5678'),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(transport.connectedSsid, 'mLRS-5678');
|
||||||
|
expect(fake.rememberedSsids, ['mLRS-5678']);
|
||||||
|
|
||||||
|
transport.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('connectedSsid is cleared on disconnect and network loss', () async {
|
||||||
|
final fake = FakeMlrsNetworkController();
|
||||||
|
final transport = await connectWithFake(
|
||||||
|
fake,
|
||||||
|
event: const MlrsNetworkAvailable(ssid: 'mLRS-5678'),
|
||||||
|
);
|
||||||
|
expect(transport.connectedSsid, 'mLRS-5678');
|
||||||
|
|
||||||
|
await transport.disconnect();
|
||||||
|
expect(transport.connectedSsid, isNull);
|
||||||
|
|
||||||
|
transport.dispose();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:drift/native.dart';
|
import 'package:drift/native.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_map/flutter_map.dart';
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
@@ -103,6 +104,19 @@ Future<ProviderContainer> _pumpWithContainer(WidgetTester tester) async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
// TopModeBar instanziiert beim Wechsel in den Fly-Modus wifiTransportProvider
|
||||||
|
// (Fortschritts-Pille/Auto-Connect-Pruefung, siehe top_mode_bar.dart) - das
|
||||||
|
// erzeugt standardmaessig einen echten MethodChannelMlrsNetworkController.
|
||||||
|
// Ohne diesen Mock-Handler wirft schon der reine dispose()-Aufruf am
|
||||||
|
// Testende MissingPluginException, weil kein natives Android-Plugin
|
||||||
|
// existiert.
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
||||||
|
.setMockMethodCallHandler(
|
||||||
|
const MethodChannel('com.dmc.dmc_app/mlrs_network'),
|
||||||
|
(call) async => null,
|
||||||
|
);
|
||||||
|
|
||||||
testWidgets('AppShell zeigt die Karte und den Plan/Fly-Umschalter im Startzustand',
|
testWidgets('AppShell zeigt die Karte und den Plan/Fly-Umschalter im Startzustand',
|
||||||
(tester) async {
|
(tester) async {
|
||||||
await tester.pumpWidget(_wrap(const AppShell()));
|
await tester.pumpWidget(_wrap(const AppShell()));
|
||||||
|
|||||||
Reference in New Issue
Block a user