Add WiZ provisioning wizard
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
class WizProvisioningDevice {
|
||||
final String bssid;
|
||||
final String? ipAddress;
|
||||
|
||||
const WizProvisioningDevice({required this.bssid, this.ipAddress});
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
enum WizProvisioningPermissionStatus { granted, requestable, settingsRequired }
|
||||
|
||||
class WizProvisioningEnvironment {
|
||||
final String platform;
|
||||
final int? androidApiLevel;
|
||||
final bool smartPairingSupported;
|
||||
final bool wifiSettingsSupported;
|
||||
final bool appSettingsSupported;
|
||||
final WizProvisioningPermissionStatus permissionStatus;
|
||||
final bool locationServicesEnabled;
|
||||
final bool connectedToWifi;
|
||||
final String? ssid;
|
||||
final String? bssid;
|
||||
final int? frequencyMhz;
|
||||
|
||||
const WizProvisioningEnvironment({
|
||||
required this.platform,
|
||||
required this.androidApiLevel,
|
||||
required this.smartPairingSupported,
|
||||
required this.wifiSettingsSupported,
|
||||
required this.appSettingsSupported,
|
||||
required this.permissionStatus,
|
||||
required this.locationServicesEnabled,
|
||||
required this.connectedToWifi,
|
||||
required this.ssid,
|
||||
required this.bssid,
|
||||
required this.frequencyMhz,
|
||||
});
|
||||
|
||||
factory WizProvisioningEnvironment.unsupported() =>
|
||||
const WizProvisioningEnvironment(
|
||||
platform: 'unknown',
|
||||
androidApiLevel: null,
|
||||
smartPairingSupported: false,
|
||||
wifiSettingsSupported: false,
|
||||
appSettingsSupported: false,
|
||||
permissionStatus: WizProvisioningPermissionStatus.granted,
|
||||
locationServicesEnabled: true,
|
||||
connectedToWifi: false,
|
||||
ssid: null,
|
||||
bssid: null,
|
||||
frequencyMhz: null,
|
||||
);
|
||||
|
||||
factory WizProvisioningEnvironment.fromMap(Map<String, dynamic> raw) {
|
||||
return WizProvisioningEnvironment(
|
||||
platform: raw['platform'] as String? ?? 'unknown',
|
||||
androidApiLevel: (raw['androidApiLevel'] as num?)?.toInt(),
|
||||
smartPairingSupported: raw['smartPairingSupported'] == true,
|
||||
wifiSettingsSupported: raw['wifiSettingsSupported'] == true,
|
||||
appSettingsSupported: raw['appSettingsSupported'] == true,
|
||||
permissionStatus: _permissionStatusFromPlatformValue(
|
||||
raw['permissionStatus'] as String?,
|
||||
),
|
||||
locationServicesEnabled: raw['locationServicesEnabled'] != false,
|
||||
connectedToWifi: raw['connectedToWifi'] == true,
|
||||
ssid: _normalizeText(raw['ssid']),
|
||||
bssid: _normalizeText(raw['bssid']),
|
||||
frequencyMhz: (raw['frequencyMhz'] as num?)?.toInt(),
|
||||
);
|
||||
}
|
||||
|
||||
bool get permissionsGranted =>
|
||||
permissionStatus == WizProvisioningPermissionStatus.granted;
|
||||
|
||||
bool get permissionRequestable =>
|
||||
permissionStatus == WizProvisioningPermissionStatus.requestable;
|
||||
|
||||
bool get requiresAppSettings =>
|
||||
permissionStatus == WizProvisioningPermissionStatus.settingsRequired;
|
||||
|
||||
bool get isAndroid => platform == 'android';
|
||||
|
||||
bool get isOn24Ghz =>
|
||||
frequencyMhz != null && frequencyMhz! >= 2400 && frequencyMhz! < 2500;
|
||||
|
||||
bool get isLikelyOn5Ghz =>
|
||||
frequencyMhz != null && frequencyMhz! >= 4900 && frequencyMhz! < 6000;
|
||||
|
||||
WizProvisioningEnvironment copyWith({
|
||||
String? platform,
|
||||
int? androidApiLevel,
|
||||
bool? smartPairingSupported,
|
||||
bool? wifiSettingsSupported,
|
||||
bool? appSettingsSupported,
|
||||
WizProvisioningPermissionStatus? permissionStatus,
|
||||
bool? locationServicesEnabled,
|
||||
bool? connectedToWifi,
|
||||
String? ssid,
|
||||
String? bssid,
|
||||
int? frequencyMhz,
|
||||
bool clearWifiInfo = false,
|
||||
}) {
|
||||
return WizProvisioningEnvironment(
|
||||
platform: platform ?? this.platform,
|
||||
androidApiLevel: androidApiLevel ?? this.androidApiLevel,
|
||||
smartPairingSupported:
|
||||
smartPairingSupported ?? this.smartPairingSupported,
|
||||
wifiSettingsSupported:
|
||||
wifiSettingsSupported ?? this.wifiSettingsSupported,
|
||||
appSettingsSupported: appSettingsSupported ?? this.appSettingsSupported,
|
||||
permissionStatus: permissionStatus ?? this.permissionStatus,
|
||||
locationServicesEnabled:
|
||||
locationServicesEnabled ?? this.locationServicesEnabled,
|
||||
connectedToWifi: connectedToWifi ?? this.connectedToWifi,
|
||||
ssid: clearWifiInfo ? null : (ssid ?? this.ssid),
|
||||
bssid: clearWifiInfo ? null : (bssid ?? this.bssid),
|
||||
frequencyMhz: clearWifiInfo ? null : (frequencyMhz ?? this.frequencyMhz),
|
||||
);
|
||||
}
|
||||
|
||||
static WizProvisioningPermissionStatus _permissionStatusFromPlatformValue(
|
||||
String? value,
|
||||
) {
|
||||
switch (value) {
|
||||
case 'granted':
|
||||
return WizProvisioningPermissionStatus.granted;
|
||||
case 'settings_required':
|
||||
return WizProvisioningPermissionStatus.settingsRequired;
|
||||
case 'requestable':
|
||||
default:
|
||||
return WizProvisioningPermissionStatus.requestable;
|
||||
}
|
||||
}
|
||||
|
||||
static String? _normalizeText(Object? raw) {
|
||||
final text = raw as String?;
|
||||
if (text == null) {
|
||||
return null;
|
||||
}
|
||||
final trimmed = text.trim();
|
||||
return trimmed.isEmpty ? null : trimmed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
enum WizProvisioningFailureKind {
|
||||
noActiveHome,
|
||||
unsupportedPlatform,
|
||||
missingPermissions,
|
||||
locationServicesDisabled,
|
||||
wifiUnavailable,
|
||||
invalidSsid,
|
||||
provisioningTimedOut,
|
||||
provisioningFailed,
|
||||
rescanFailed,
|
||||
}
|
||||
|
||||
class WizProvisioningFailure {
|
||||
final WizProvisioningFailureKind kind;
|
||||
final String message;
|
||||
final String? details;
|
||||
|
||||
const WizProvisioningFailure({
|
||||
required this.kind,
|
||||
required this.message,
|
||||
this.details,
|
||||
});
|
||||
}
|
||||
114
lib/features/provisioning/models/wiz_provisioning_state.dart
Normal file
114
lib/features/provisioning/models/wiz_provisioning_state.dart
Normal file
@@ -0,0 +1,114 @@
|
||||
import 'wiz_provisioning_device.dart';
|
||||
import 'wiz_provisioning_environment.dart';
|
||||
import 'wiz_provisioning_failure.dart';
|
||||
|
||||
enum WizProvisioningStatus {
|
||||
initial,
|
||||
loadingEnvironment,
|
||||
attentionRequired,
|
||||
ready,
|
||||
provisioning,
|
||||
rescanning,
|
||||
success,
|
||||
failure,
|
||||
unsupported,
|
||||
}
|
||||
|
||||
class WizRescanSummary {
|
||||
final int found;
|
||||
final int added;
|
||||
final int updated;
|
||||
final int removedOffline;
|
||||
final int pendingRemoval;
|
||||
final int online;
|
||||
|
||||
const WizRescanSummary({
|
||||
required this.found,
|
||||
required this.added,
|
||||
required this.updated,
|
||||
required this.removedOffline,
|
||||
required this.pendingRemoval,
|
||||
required this.online,
|
||||
});
|
||||
|
||||
factory WizRescanSummary.fromMap(Map<String, dynamic> raw) {
|
||||
return WizRescanSummary(
|
||||
found: (raw['found'] as num?)?.toInt() ?? 0,
|
||||
added: (raw['added'] as num?)?.toInt() ?? 0,
|
||||
updated: (raw['updated'] as num?)?.toInt() ?? 0,
|
||||
removedOffline: (raw['removed_offline'] as num?)?.toInt() ?? 0,
|
||||
pendingRemoval: (raw['pending_removal'] as num?)?.toInt() ?? 0,
|
||||
online: (raw['online'] as num?)?.toInt() ?? 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class WizProvisioningState {
|
||||
final WizProvisioningStatus status;
|
||||
final WizProvisioningEnvironment environment;
|
||||
final String? activeHomeName;
|
||||
final WizProvisioningFailure? failure;
|
||||
final WizRescanSummary? rescanSummary;
|
||||
final List<WizProvisioningDevice> provisionedDevices;
|
||||
final List<String> timeline;
|
||||
final String? notice;
|
||||
|
||||
const WizProvisioningState({
|
||||
required this.status,
|
||||
required this.environment,
|
||||
required this.activeHomeName,
|
||||
required this.failure,
|
||||
required this.rescanSummary,
|
||||
required this.provisionedDevices,
|
||||
required this.timeline,
|
||||
required this.notice,
|
||||
});
|
||||
|
||||
factory WizProvisioningState.initial() => WizProvisioningState(
|
||||
status: WizProvisioningStatus.initial,
|
||||
environment: WizProvisioningEnvironment.unsupported(),
|
||||
activeHomeName: null,
|
||||
failure: null,
|
||||
rescanSummary: null,
|
||||
provisionedDevices: const [],
|
||||
timeline: const [],
|
||||
notice: null,
|
||||
);
|
||||
|
||||
bool get isBusy =>
|
||||
status == WizProvisioningStatus.loadingEnvironment ||
|
||||
status == WizProvisioningStatus.provisioning ||
|
||||
status == WizProvisioningStatus.rescanning;
|
||||
|
||||
bool get canStart =>
|
||||
status == WizProvisioningStatus.ready ||
|
||||
status == WizProvisioningStatus.failure ||
|
||||
status == WizProvisioningStatus.attentionRequired;
|
||||
|
||||
WizProvisioningState copyWith({
|
||||
WizProvisioningStatus? status,
|
||||
WizProvisioningEnvironment? environment,
|
||||
String? activeHomeName,
|
||||
WizProvisioningFailure? failure,
|
||||
bool clearFailure = false,
|
||||
WizRescanSummary? rescanSummary,
|
||||
bool clearRescanSummary = false,
|
||||
List<WizProvisioningDevice>? provisionedDevices,
|
||||
List<String>? timeline,
|
||||
String? notice,
|
||||
bool clearNotice = false,
|
||||
}) {
|
||||
return WizProvisioningState(
|
||||
status: status ?? this.status,
|
||||
environment: environment ?? this.environment,
|
||||
activeHomeName: activeHomeName ?? this.activeHomeName,
|
||||
failure: clearFailure ? null : (failure ?? this.failure),
|
||||
rescanSummary: clearRescanSummary
|
||||
? null
|
||||
: (rescanSummary ?? this.rescanSummary),
|
||||
provisionedDevices: provisionedDevices ?? this.provisionedDevices,
|
||||
timeline: timeline ?? this.timeline,
|
||||
notice: clearNotice ? null : (notice ?? this.notice),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
class WizProvisioningTiming {
|
||||
final Duration provisioningTimeout;
|
||||
final Duration settleAfterFirstResponse;
|
||||
final Duration initialRescanDelay;
|
||||
final Duration retryRescanDelay;
|
||||
final int maxRescanAttempts;
|
||||
|
||||
const WizProvisioningTiming({
|
||||
this.provisioningTimeout = const Duration(seconds: 45),
|
||||
this.settleAfterFirstResponse = const Duration(seconds: 3),
|
||||
this.initialRescanDelay = const Duration(seconds: 3),
|
||||
this.retryRescanDelay = const Duration(seconds: 4),
|
||||
this.maxRescanAttempts = 3,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user