From 973fc2490c2d419cf6e7b10dbebd1096fe087f72 Mon Sep 17 00:00:00 2001 From: JulianAlcala Date: Fri, 17 Apr 2026 03:06:23 +0200 Subject: [PATCH] feat(wifi-settings): redesign with device commands, WebSocket scan, and connect flow --- .../datasources/wifi_remote_datasource.dart | 13 +- .../wifi_remote_datasource_impl.dart | 27 +- .../create_wifi_network_request_model.dart | 3 +- ...te_wifi_network_request_model.freezed.dart | 45 +-- .../create_wifi_network_request_model.g.dart | 6 +- .../get_wifi_networks_response_model.dart | 27 +- ..._wifi_networks_response_model.freezed.dart | 61 ++-- .../get_wifi_networks_response_model.g.dart | 24 +- .../repositories/wifi_repository_impl.dart | 46 +-- .../domain/repositories/wifi_repository.dart | 8 +- .../presentation/settings_screen.dart | 23 +- .../domain/entities/scanned_wifi_network.dart | 11 + .../scanned_wifi_network.freezed.dart | 274 ++++++++++++++ .../domain/entities/wifi_network_entity.dart | 3 + .../entities/wifi_network_entity.freezed.dart | 49 +-- .../state/wifi_settings_view_model.dart | 244 +++++++++++-- .../state/wifi_settings_view_state.dart | 17 +- .../wifi_settings_view_state.freezed.dart | 124 +++++-- .../widgets/add_wifi_network_sheet.dart | 88 ++++- .../widgets/available_wifi_network_card.dart | 84 +++++ .../presentation/wifi_settings_screen.dart | 334 ++++++++++++------ .../models/send_command_request_model.dart | 8 + .../models/send_command_request_model.g.dart | 4 + packages/sf_localizations/assets/l10n/de.json | 16 + packages/sf_localizations/assets/l10n/en.json | 16 + packages/sf_localizations/assets/l10n/es.json | 16 + packages/sf_localizations/assets/l10n/fr.json | 16 + packages/sf_localizations/assets/l10n/it.json | 16 + packages/sf_localizations/assets/l10n/pt.json | 16 + .../lib/src/generated/i18n.dart | 16 + 30 files changed, 1297 insertions(+), 338 deletions(-) create mode 100644 modules/legacy/modules/settings/lib/src/features/wifi_settings/domain/entities/scanned_wifi_network.dart create mode 100644 modules/legacy/modules/settings/lib/src/features/wifi_settings/domain/entities/scanned_wifi_network.freezed.dart create mode 100644 modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/widgets/available_wifi_network_card.dart diff --git a/modules/legacy/modules/settings/lib/src/core/data/datasources/wifi_remote_datasource.dart b/modules/legacy/modules/settings/lib/src/core/data/datasources/wifi_remote_datasource.dart index 1d8a5174..9b180139 100644 --- a/modules/legacy/modules/settings/lib/src/core/data/datasources/wifi_remote_datasource.dart +++ b/modules/legacy/modules/settings/lib/src/core/data/datasources/wifi_remote_datasource.dart @@ -1,13 +1,16 @@ -import 'package:settings/src/core/data/models/create_wifi_network_request_model.dart'; -import 'package:settings/src/core/data/models/get_wifi_networks_response_model.dart'; +import 'package:settings/src/features/wifi_settings/domain/entities/wifi_network_entity.dart'; abstract class WifiRemoteDatasource { - Future getWifiNetworks({ - required String deviceId, + Future> getWifiNetworks({ + required String deviceIdentificator, }); Future createWifiNetwork({ - required CreateWifiNetworkRequestModel request, + required String id, + required String deviceIdentificator, + required String ssid, + required String bssid, + required String password, }); Future deleteWifiNetwork({required String networkId}); diff --git a/modules/legacy/modules/settings/lib/src/core/data/datasources/wifi_remote_datasource_impl.dart b/modules/legacy/modules/settings/lib/src/core/data/datasources/wifi_remote_datasource_impl.dart index c67349c1..17f08de1 100644 --- a/modules/legacy/modules/settings/lib/src/core/data/datasources/wifi_remote_datasource_impl.dart +++ b/modules/legacy/modules/settings/lib/src/core/data/datasources/wifi_remote_datasource_impl.dart @@ -2,6 +2,7 @@ import 'package:dio/dio.dart'; import 'package:legacy_shared/legacy_shared.dart'; import 'package:sf_infrastructure/sf_infrastructure.dart'; +import '../../../features/wifi_settings/domain/entities/wifi_network_entity.dart'; import '../models/create_wifi_network_request_model.dart'; import '../models/get_wifi_networks_response_model.dart'; import 'wifi_remote_datasource.dart'; @@ -12,29 +13,39 @@ class WifiRemoteDatasourceImpl implements WifiRemoteDatasource { final SaveFamilyRepository _repository; @override - Future getWifiNetworks({ - required String deviceId, + Future> getWifiNetworks({ + required String deviceIdentificator, }) async { try { final response = await _repository.get>( - '/devices/$deviceId/wifi-networks', + '/devices/identificator/$deviceIdentificator/wifi-networks', ); final data = response.data; - if (data == null || data.isEmpty) { - return const GetWifiNetworksResponseModel(total: 0, items: []); - } + if (data == null || data.isEmpty) return []; - return GetWifiNetworksResponseModel.fromJson(data); + return GetWifiNetworksResponseModel.fromJson(data).toEntities(); } on DioException catch (error) { + if (error.response?.statusCode == 404) return []; throw mapDioError(error, defaultMessage: 'Error getting WiFi networks'); } } @override Future createWifiNetwork({ - required CreateWifiNetworkRequestModel request, + required String id, + required String deviceIdentificator, + required String ssid, + required String bssid, + required String password, }) async { + final request = CreateWifiNetworkRequestModel( + id: id, + deviceIdentificator: deviceIdentificator, + ssid: ssid, + bssid: bssid, + password: password, + ); await safeCall( () => _repository.post('/wifi-networks', body: request.toJson()), 'Error creating WiFi network', diff --git a/modules/legacy/modules/settings/lib/src/core/data/models/create_wifi_network_request_model.dart b/modules/legacy/modules/settings/lib/src/core/data/models/create_wifi_network_request_model.dart index d85fc8b4..abaa3ca9 100644 --- a/modules/legacy/modules/settings/lib/src/core/data/models/create_wifi_network_request_model.dart +++ b/modules/legacy/modules/settings/lib/src/core/data/models/create_wifi_network_request_model.dart @@ -8,9 +8,10 @@ abstract class CreateWifiNetworkRequestModel with _$CreateWifiNetworkRequestModel { const factory CreateWifiNetworkRequestModel({ required String id, - required String deviceId, + required String deviceIdentificator, required String ssid, required String bssid, + required String password, }) = _CreateWifiNetworkRequestModel; factory CreateWifiNetworkRequestModel.fromJson(Map json) => diff --git a/modules/legacy/modules/settings/lib/src/core/data/models/create_wifi_network_request_model.freezed.dart b/modules/legacy/modules/settings/lib/src/core/data/models/create_wifi_network_request_model.freezed.dart index f29912fe..a2d89a72 100644 --- a/modules/legacy/modules/settings/lib/src/core/data/models/create_wifi_network_request_model.freezed.dart +++ b/modules/legacy/modules/settings/lib/src/core/data/models/create_wifi_network_request_model.freezed.dart @@ -15,7 +15,7 @@ T _$identity(T value) => value; /// @nodoc mixin _$CreateWifiNetworkRequestModel { - String get id; String get deviceId; String get ssid; String get bssid; + String get id; String get deviceIdentificator; String get ssid; String get bssid; String get password; /// Create a copy of CreateWifiNetworkRequestModel /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -28,16 +28,16 @@ $CreateWifiNetworkRequestModelCopyWith get copyWi @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is CreateWifiNetworkRequestModel&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.ssid, ssid) || other.ssid == ssid)&&(identical(other.bssid, bssid) || other.bssid == bssid)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is CreateWifiNetworkRequestModel&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceIdentificator, deviceIdentificator) || other.deviceIdentificator == deviceIdentificator)&&(identical(other.ssid, ssid) || other.ssid == ssid)&&(identical(other.bssid, bssid) || other.bssid == bssid)&&(identical(other.password, password) || other.password == password)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,deviceId,ssid,bssid); +int get hashCode => Object.hash(runtimeType,id,deviceIdentificator,ssid,bssid,password); @override String toString() { - return 'CreateWifiNetworkRequestModel(id: $id, deviceId: $deviceId, ssid: $ssid, bssid: $bssid)'; + return 'CreateWifiNetworkRequestModel(id: $id, deviceIdentificator: $deviceIdentificator, ssid: $ssid, bssid: $bssid, password: $password)'; } @@ -48,7 +48,7 @@ abstract mixin class $CreateWifiNetworkRequestModelCopyWith<$Res> { factory $CreateWifiNetworkRequestModelCopyWith(CreateWifiNetworkRequestModel value, $Res Function(CreateWifiNetworkRequestModel) _then) = _$CreateWifiNetworkRequestModelCopyWithImpl; @useResult $Res call({ - String id, String deviceId, String ssid, String bssid + String id, String deviceIdentificator, String ssid, String bssid, String password }); @@ -65,12 +65,13 @@ class _$CreateWifiNetworkRequestModelCopyWithImpl<$Res> /// Create a copy of CreateWifiNetworkRequestModel /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? deviceId = null,Object? ssid = null,Object? bssid = null,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? deviceIdentificator = null,Object? ssid = null,Object? bssid = null,Object? password = null,}) { return _then(_self.copyWith( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable -as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable +as String,deviceIdentificator: null == deviceIdentificator ? _self.deviceIdentificator : deviceIdentificator // ignore: cast_nullable_to_non_nullable as String,ssid: null == ssid ? _self.ssid : ssid // ignore: cast_nullable_to_non_nullable as String,bssid: null == bssid ? _self.bssid : bssid // ignore: cast_nullable_to_non_nullable +as String,password: null == password ? _self.password : password // ignore: cast_nullable_to_non_nullable as String, )); } @@ -156,10 +157,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String deviceId, String ssid, String bssid)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String deviceIdentificator, String ssid, String bssid, String password)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _CreateWifiNetworkRequestModel() when $default != null: -return $default(_that.id,_that.deviceId,_that.ssid,_that.bssid);case _: +return $default(_that.id,_that.deviceIdentificator,_that.ssid,_that.bssid,_that.password);case _: return orElse(); } @@ -177,10 +178,10 @@ return $default(_that.id,_that.deviceId,_that.ssid,_that.bssid);case _: /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( String id, String deviceId, String ssid, String bssid) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( String id, String deviceIdentificator, String ssid, String bssid, String password) $default,) {final _that = this; switch (_that) { case _CreateWifiNetworkRequestModel(): -return $default(_that.id,_that.deviceId,_that.ssid,_that.bssid);case _: +return $default(_that.id,_that.deviceIdentificator,_that.ssid,_that.bssid,_that.password);case _: throw StateError('Unexpected subclass'); } @@ -197,10 +198,10 @@ return $default(_that.id,_that.deviceId,_that.ssid,_that.bssid);case _: /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String deviceId, String ssid, String bssid)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String deviceIdentificator, String ssid, String bssid, String password)? $default,) {final _that = this; switch (_that) { case _CreateWifiNetworkRequestModel() when $default != null: -return $default(_that.id,_that.deviceId,_that.ssid,_that.bssid);case _: +return $default(_that.id,_that.deviceIdentificator,_that.ssid,_that.bssid,_that.password);case _: return null; } @@ -212,13 +213,14 @@ return $default(_that.id,_that.deviceId,_that.ssid,_that.bssid);case _: @JsonSerializable() class _CreateWifiNetworkRequestModel implements CreateWifiNetworkRequestModel { - const _CreateWifiNetworkRequestModel({required this.id, required this.deviceId, required this.ssid, required this.bssid}); + const _CreateWifiNetworkRequestModel({required this.id, required this.deviceIdentificator, required this.ssid, required this.bssid, required this.password}); factory _CreateWifiNetworkRequestModel.fromJson(Map json) => _$CreateWifiNetworkRequestModelFromJson(json); @override final String id; -@override final String deviceId; +@override final String deviceIdentificator; @override final String ssid; @override final String bssid; +@override final String password; /// Create a copy of CreateWifiNetworkRequestModel /// with the given fields replaced by the non-null parameter values. @@ -233,16 +235,16 @@ Map toJson() { @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _CreateWifiNetworkRequestModel&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.ssid, ssid) || other.ssid == ssid)&&(identical(other.bssid, bssid) || other.bssid == bssid)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _CreateWifiNetworkRequestModel&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceIdentificator, deviceIdentificator) || other.deviceIdentificator == deviceIdentificator)&&(identical(other.ssid, ssid) || other.ssid == ssid)&&(identical(other.bssid, bssid) || other.bssid == bssid)&&(identical(other.password, password) || other.password == password)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,deviceId,ssid,bssid); +int get hashCode => Object.hash(runtimeType,id,deviceIdentificator,ssid,bssid,password); @override String toString() { - return 'CreateWifiNetworkRequestModel(id: $id, deviceId: $deviceId, ssid: $ssid, bssid: $bssid)'; + return 'CreateWifiNetworkRequestModel(id: $id, deviceIdentificator: $deviceIdentificator, ssid: $ssid, bssid: $bssid, password: $password)'; } @@ -253,7 +255,7 @@ abstract mixin class _$CreateWifiNetworkRequestModelCopyWith<$Res> implements $C factory _$CreateWifiNetworkRequestModelCopyWith(_CreateWifiNetworkRequestModel value, $Res Function(_CreateWifiNetworkRequestModel) _then) = __$CreateWifiNetworkRequestModelCopyWithImpl; @override @useResult $Res call({ - String id, String deviceId, String ssid, String bssid + String id, String deviceIdentificator, String ssid, String bssid, String password }); @@ -270,12 +272,13 @@ class __$CreateWifiNetworkRequestModelCopyWithImpl<$Res> /// Create a copy of CreateWifiNetworkRequestModel /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? deviceId = null,Object? ssid = null,Object? bssid = null,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? deviceIdentificator = null,Object? ssid = null,Object? bssid = null,Object? password = null,}) { return _then(_CreateWifiNetworkRequestModel( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable -as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable +as String,deviceIdentificator: null == deviceIdentificator ? _self.deviceIdentificator : deviceIdentificator // ignore: cast_nullable_to_non_nullable as String,ssid: null == ssid ? _self.ssid : ssid // ignore: cast_nullable_to_non_nullable as String,bssid: null == bssid ? _self.bssid : bssid // ignore: cast_nullable_to_non_nullable +as String,password: null == password ? _self.password : password // ignore: cast_nullable_to_non_nullable as String, )); } diff --git a/modules/legacy/modules/settings/lib/src/core/data/models/create_wifi_network_request_model.g.dart b/modules/legacy/modules/settings/lib/src/core/data/models/create_wifi_network_request_model.g.dart index 59cb7ce7..b64bc5ce 100644 --- a/modules/legacy/modules/settings/lib/src/core/data/models/create_wifi_network_request_model.g.dart +++ b/modules/legacy/modules/settings/lib/src/core/data/models/create_wifi_network_request_model.g.dart @@ -10,16 +10,18 @@ _CreateWifiNetworkRequestModel _$CreateWifiNetworkRequestModelFromJson( Map json, ) => _CreateWifiNetworkRequestModel( id: json['id'] as String, - deviceId: json['deviceId'] as String, + deviceIdentificator: json['deviceIdentificator'] as String, ssid: json['ssid'] as String, bssid: json['bssid'] as String, + password: json['password'] as String, ); Map _$CreateWifiNetworkRequestModelToJson( _CreateWifiNetworkRequestModel instance, ) => { 'id': instance.id, - 'deviceId': instance.deviceId, + 'deviceIdentificator': instance.deviceIdentificator, 'ssid': instance.ssid, 'bssid': instance.bssid, + 'password': instance.password, }; diff --git a/modules/legacy/modules/settings/lib/src/core/data/models/get_wifi_networks_response_model.dart b/modules/legacy/modules/settings/lib/src/core/data/models/get_wifi_networks_response_model.dart index d11f69a5..0fc7b939 100644 --- a/modules/legacy/modules/settings/lib/src/core/data/models/get_wifi_networks_response_model.dart +++ b/modules/legacy/modules/settings/lib/src/core/data/models/get_wifi_networks_response_model.dart @@ -1,4 +1,5 @@ import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:settings/src/features/wifi_settings/domain/entities/wifi_network_entity.dart'; part 'get_wifi_networks_response_model.freezed.dart'; part 'get_wifi_networks_response_model.g.dart'; @@ -7,8 +8,8 @@ part 'get_wifi_networks_response_model.g.dart'; abstract class GetWifiNetworksResponseModel with _$GetWifiNetworksResponseModel { const factory GetWifiNetworksResponseModel({ - required int total, - required List items, + @Default(0) int total, + @Default([]) List items, }) = _GetWifiNetworksResponseModel; factory GetWifiNetworksResponseModel.fromJson(Map json) => @@ -20,13 +21,31 @@ abstract class WifiNetworkItemResponseModel with _$WifiNetworkItemResponseModel { const factory WifiNetworkItemResponseModel({ required String id, - required String deviceId, + @Default('') String deviceIdentificator, required String ssid, required String bssid, - required int createdAt, + String? password, + int? createdAt, int? updatedAt, }) = _WifiNetworkItemResponseModel; factory WifiNetworkItemResponseModel.fromJson(Map json) => _$WifiNetworkItemResponseModelFromJson(json); } + +extension WifiNetworkResponseMapper on GetWifiNetworksResponseModel { + List toEntities() { + return items + .map( + (item) => WifiNetworkEntity( + id: item.id, + ssid: item.ssid, + bssid: item.bssid, + password: item.password, + deviceIdentificator: item.deviceIdentificator, + createdAt: item.createdAt, + ), + ) + .toList(); + } +} diff --git a/modules/legacy/modules/settings/lib/src/core/data/models/get_wifi_networks_response_model.freezed.dart b/modules/legacy/modules/settings/lib/src/core/data/models/get_wifi_networks_response_model.freezed.dart index da20470f..002043c4 100644 --- a/modules/legacy/modules/settings/lib/src/core/data/models/get_wifi_networks_response_model.freezed.dart +++ b/modules/legacy/modules/settings/lib/src/core/data/models/get_wifi_networks_response_model.freezed.dart @@ -210,12 +210,12 @@ return $default(_that.total,_that.items);case _: @JsonSerializable() class _GetWifiNetworksResponseModel implements GetWifiNetworksResponseModel { - const _GetWifiNetworksResponseModel({required this.total, required final List items}): _items = items; + const _GetWifiNetworksResponseModel({this.total = 0, final List items = const []}): _items = items; factory _GetWifiNetworksResponseModel.fromJson(Map json) => _$GetWifiNetworksResponseModelFromJson(json); -@override final int total; +@override@JsonKey() final int total; final List _items; -@override List get items { +@override@JsonKey() List get items { if (_items is EqualUnmodifiableListView) return _items; // ignore: implicit_dynamic_type return EqualUnmodifiableListView(_items); @@ -287,7 +287,7 @@ as List, /// @nodoc mixin _$WifiNetworkItemResponseModel { - String get id; String get deviceId; String get ssid; String get bssid; int get createdAt; int? get updatedAt; + String get id; String get deviceIdentificator; String get ssid; String get bssid; String? get password; int? get createdAt; int? get updatedAt; /// Create a copy of WifiNetworkItemResponseModel /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -300,16 +300,16 @@ $WifiNetworkItemResponseModelCopyWith get copyWith @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is WifiNetworkItemResponseModel&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.ssid, ssid) || other.ssid == ssid)&&(identical(other.bssid, bssid) || other.bssid == bssid)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is WifiNetworkItemResponseModel&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceIdentificator, deviceIdentificator) || other.deviceIdentificator == deviceIdentificator)&&(identical(other.ssid, ssid) || other.ssid == ssid)&&(identical(other.bssid, bssid) || other.bssid == bssid)&&(identical(other.password, password) || other.password == password)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,deviceId,ssid,bssid,createdAt,updatedAt); +int get hashCode => Object.hash(runtimeType,id,deviceIdentificator,ssid,bssid,password,createdAt,updatedAt); @override String toString() { - return 'WifiNetworkItemResponseModel(id: $id, deviceId: $deviceId, ssid: $ssid, bssid: $bssid, createdAt: $createdAt, updatedAt: $updatedAt)'; + return 'WifiNetworkItemResponseModel(id: $id, deviceIdentificator: $deviceIdentificator, ssid: $ssid, bssid: $bssid, password: $password, createdAt: $createdAt, updatedAt: $updatedAt)'; } @@ -320,7 +320,7 @@ abstract mixin class $WifiNetworkItemResponseModelCopyWith<$Res> { factory $WifiNetworkItemResponseModelCopyWith(WifiNetworkItemResponseModel value, $Res Function(WifiNetworkItemResponseModel) _then) = _$WifiNetworkItemResponseModelCopyWithImpl; @useResult $Res call({ - String id, String deviceId, String ssid, String bssid, int createdAt, int? updatedAt + String id, String deviceIdentificator, String ssid, String bssid, String? password, int? createdAt, int? updatedAt }); @@ -337,14 +337,15 @@ class _$WifiNetworkItemResponseModelCopyWithImpl<$Res> /// Create a copy of WifiNetworkItemResponseModel /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? deviceId = null,Object? ssid = null,Object? bssid = null,Object? createdAt = null,Object? updatedAt = freezed,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? deviceIdentificator = null,Object? ssid = null,Object? bssid = null,Object? password = freezed,Object? createdAt = freezed,Object? updatedAt = freezed,}) { return _then(_self.copyWith( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable -as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable +as String,deviceIdentificator: null == deviceIdentificator ? _self.deviceIdentificator : deviceIdentificator // ignore: cast_nullable_to_non_nullable as String,ssid: null == ssid ? _self.ssid : ssid // ignore: cast_nullable_to_non_nullable as String,bssid: null == bssid ? _self.bssid : bssid // ignore: cast_nullable_to_non_nullable -as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable -as int,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable +as String,password: freezed == password ? _self.password : password // ignore: cast_nullable_to_non_nullable +as String?,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as int?,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable as int?, )); } @@ -430,10 +431,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String deviceId, String ssid, String bssid, int createdAt, int? updatedAt)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String deviceIdentificator, String ssid, String bssid, String? password, int? createdAt, int? updatedAt)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _WifiNetworkItemResponseModel() when $default != null: -return $default(_that.id,_that.deviceId,_that.ssid,_that.bssid,_that.createdAt,_that.updatedAt);case _: +return $default(_that.id,_that.deviceIdentificator,_that.ssid,_that.bssid,_that.password,_that.createdAt,_that.updatedAt);case _: return orElse(); } @@ -451,10 +452,10 @@ return $default(_that.id,_that.deviceId,_that.ssid,_that.bssid,_that.createdAt,_ /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( String id, String deviceId, String ssid, String bssid, int createdAt, int? updatedAt) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( String id, String deviceIdentificator, String ssid, String bssid, String? password, int? createdAt, int? updatedAt) $default,) {final _that = this; switch (_that) { case _WifiNetworkItemResponseModel(): -return $default(_that.id,_that.deviceId,_that.ssid,_that.bssid,_that.createdAt,_that.updatedAt);case _: +return $default(_that.id,_that.deviceIdentificator,_that.ssid,_that.bssid,_that.password,_that.createdAt,_that.updatedAt);case _: throw StateError('Unexpected subclass'); } @@ -471,10 +472,10 @@ return $default(_that.id,_that.deviceId,_that.ssid,_that.bssid,_that.createdAt,_ /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String deviceId, String ssid, String bssid, int createdAt, int? updatedAt)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String deviceIdentificator, String ssid, String bssid, String? password, int? createdAt, int? updatedAt)? $default,) {final _that = this; switch (_that) { case _WifiNetworkItemResponseModel() when $default != null: -return $default(_that.id,_that.deviceId,_that.ssid,_that.bssid,_that.createdAt,_that.updatedAt);case _: +return $default(_that.id,_that.deviceIdentificator,_that.ssid,_that.bssid,_that.password,_that.createdAt,_that.updatedAt);case _: return null; } @@ -486,14 +487,15 @@ return $default(_that.id,_that.deviceId,_that.ssid,_that.bssid,_that.createdAt,_ @JsonSerializable() class _WifiNetworkItemResponseModel implements WifiNetworkItemResponseModel { - const _WifiNetworkItemResponseModel({required this.id, required this.deviceId, required this.ssid, required this.bssid, required this.createdAt, this.updatedAt}); + const _WifiNetworkItemResponseModel({required this.id, this.deviceIdentificator = '', required this.ssid, required this.bssid, this.password, this.createdAt, this.updatedAt}); factory _WifiNetworkItemResponseModel.fromJson(Map json) => _$WifiNetworkItemResponseModelFromJson(json); @override final String id; -@override final String deviceId; +@override@JsonKey() final String deviceIdentificator; @override final String ssid; @override final String bssid; -@override final int createdAt; +@override final String? password; +@override final int? createdAt; @override final int? updatedAt; /// Create a copy of WifiNetworkItemResponseModel @@ -509,16 +511,16 @@ Map toJson() { @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _WifiNetworkItemResponseModel&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.ssid, ssid) || other.ssid == ssid)&&(identical(other.bssid, bssid) || other.bssid == bssid)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _WifiNetworkItemResponseModel&&(identical(other.id, id) || other.id == id)&&(identical(other.deviceIdentificator, deviceIdentificator) || other.deviceIdentificator == deviceIdentificator)&&(identical(other.ssid, ssid) || other.ssid == ssid)&&(identical(other.bssid, bssid) || other.bssid == bssid)&&(identical(other.password, password) || other.password == password)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,deviceId,ssid,bssid,createdAt,updatedAt); +int get hashCode => Object.hash(runtimeType,id,deviceIdentificator,ssid,bssid,password,createdAt,updatedAt); @override String toString() { - return 'WifiNetworkItemResponseModel(id: $id, deviceId: $deviceId, ssid: $ssid, bssid: $bssid, createdAt: $createdAt, updatedAt: $updatedAt)'; + return 'WifiNetworkItemResponseModel(id: $id, deviceIdentificator: $deviceIdentificator, ssid: $ssid, bssid: $bssid, password: $password, createdAt: $createdAt, updatedAt: $updatedAt)'; } @@ -529,7 +531,7 @@ abstract mixin class _$WifiNetworkItemResponseModelCopyWith<$Res> implements $Wi factory _$WifiNetworkItemResponseModelCopyWith(_WifiNetworkItemResponseModel value, $Res Function(_WifiNetworkItemResponseModel) _then) = __$WifiNetworkItemResponseModelCopyWithImpl; @override @useResult $Res call({ - String id, String deviceId, String ssid, String bssid, int createdAt, int? updatedAt + String id, String deviceIdentificator, String ssid, String bssid, String? password, int? createdAt, int? updatedAt }); @@ -546,14 +548,15 @@ class __$WifiNetworkItemResponseModelCopyWithImpl<$Res> /// Create a copy of WifiNetworkItemResponseModel /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? deviceId = null,Object? ssid = null,Object? bssid = null,Object? createdAt = null,Object? updatedAt = freezed,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? deviceIdentificator = null,Object? ssid = null,Object? bssid = null,Object? password = freezed,Object? createdAt = freezed,Object? updatedAt = freezed,}) { return _then(_WifiNetworkItemResponseModel( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable -as String,deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable +as String,deviceIdentificator: null == deviceIdentificator ? _self.deviceIdentificator : deviceIdentificator // ignore: cast_nullable_to_non_nullable as String,ssid: null == ssid ? _self.ssid : ssid // ignore: cast_nullable_to_non_nullable as String,bssid: null == bssid ? _self.bssid : bssid // ignore: cast_nullable_to_non_nullable -as String,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable -as int,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable +as String,password: freezed == password ? _self.password : password // ignore: cast_nullable_to_non_nullable +as String?,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as int?,updatedAt: freezed == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable as int?, )); } diff --git a/modules/legacy/modules/settings/lib/src/core/data/models/get_wifi_networks_response_model.g.dart b/modules/legacy/modules/settings/lib/src/core/data/models/get_wifi_networks_response_model.g.dart index d489a226..85d9e2ae 100644 --- a/modules/legacy/modules/settings/lib/src/core/data/models/get_wifi_networks_response_model.g.dart +++ b/modules/legacy/modules/settings/lib/src/core/data/models/get_wifi_networks_response_model.g.dart @@ -9,12 +9,16 @@ part of 'get_wifi_networks_response_model.dart'; _GetWifiNetworksResponseModel _$GetWifiNetworksResponseModelFromJson( Map json, ) => _GetWifiNetworksResponseModel( - total: (json['total'] as num).toInt(), - items: (json['items'] as List) - .map( - (e) => WifiNetworkItemResponseModel.fromJson(e as Map), - ) - .toList(), + total: (json['total'] as num?)?.toInt() ?? 0, + items: + (json['items'] as List?) + ?.map( + (e) => WifiNetworkItemResponseModel.fromJson( + e as Map, + ), + ) + .toList() ?? + const [], ); Map _$GetWifiNetworksResponseModelToJson( @@ -25,10 +29,11 @@ _WifiNetworkItemResponseModel _$WifiNetworkItemResponseModelFromJson( Map json, ) => _WifiNetworkItemResponseModel( id: json['id'] as String, - deviceId: json['deviceId'] as String, + deviceIdentificator: json['deviceIdentificator'] as String? ?? '', ssid: json['ssid'] as String, bssid: json['bssid'] as String, - createdAt: (json['createdAt'] as num).toInt(), + password: json['password'] as String?, + createdAt: (json['createdAt'] as num?)?.toInt(), updatedAt: (json['updatedAt'] as num?)?.toInt(), ); @@ -36,9 +41,10 @@ Map _$WifiNetworkItemResponseModelToJson( _WifiNetworkItemResponseModel instance, ) => { 'id': instance.id, - 'deviceId': instance.deviceId, + 'deviceIdentificator': instance.deviceIdentificator, 'ssid': instance.ssid, 'bssid': instance.bssid, + 'password': instance.password, 'createdAt': instance.createdAt, 'updatedAt': instance.updatedAt, }; diff --git a/modules/legacy/modules/settings/lib/src/core/data/repositories/wifi_repository_impl.dart b/modules/legacy/modules/settings/lib/src/core/data/repositories/wifi_repository_impl.dart index 165b7b88..bdc09ef9 100644 --- a/modules/legacy/modules/settings/lib/src/core/data/repositories/wifi_repository_impl.dart +++ b/modules/legacy/modules/settings/lib/src/core/data/repositories/wifi_repository_impl.dart @@ -1,51 +1,33 @@ -import 'package:uuid/uuid.dart'; - import '../../../features/wifi_settings/domain/entities/wifi_network_entity.dart'; import '../../domain/repositories/wifi_repository.dart'; import '../datasources/wifi_remote_datasource.dart'; -import '../models/create_wifi_network_request_model.dart'; class WifiRepositoryImpl implements WifiRepository { WifiRepositoryImpl(this._datasource); - static const _uuid = Uuid(); final WifiRemoteDatasource _datasource; @override Future> getWifiNetworks({ - required String deviceId, - }) async { - final response = await _datasource.getWifiNetworks(deviceId: deviceId); - - return response.items - .map( - (item) => WifiNetworkEntity( - id: item.id, - ssid: item.ssid, - bssid: item.bssid, - ), - ) - .toList(); - } + required String deviceIdentificator, + }) => _datasource.getWifiNetworks(deviceIdentificator: deviceIdentificator); @override Future createWifiNetwork({ - required String deviceId, + required String id, + required String deviceIdentificator, required String ssid, required String bssid, - }) async { - final request = CreateWifiNetworkRequestModel( - id: _uuid.v4(), - deviceId: deviceId, - ssid: ssid, - bssid: bssid, - ); - - await _datasource.createWifiNetwork(request: request); - } + required String password, + }) => _datasource.createWifiNetwork( + id: id, + deviceIdentificator: deviceIdentificator, + ssid: ssid, + bssid: bssid, + password: password, + ); @override - Future deleteWifiNetwork({required String networkId}) { - return _datasource.deleteWifiNetwork(networkId: networkId); - } + Future deleteWifiNetwork({required String networkId}) => + _datasource.deleteWifiNetwork(networkId: networkId); } diff --git a/modules/legacy/modules/settings/lib/src/core/domain/repositories/wifi_repository.dart b/modules/legacy/modules/settings/lib/src/core/domain/repositories/wifi_repository.dart index 549cdaf4..91c6c733 100644 --- a/modules/legacy/modules/settings/lib/src/core/domain/repositories/wifi_repository.dart +++ b/modules/legacy/modules/settings/lib/src/core/domain/repositories/wifi_repository.dart @@ -1,12 +1,16 @@ import 'package:settings/src/features/wifi_settings/domain/entities/wifi_network_entity.dart'; abstract class WifiRepository { - Future> getWifiNetworks({required String deviceId}); + Future> getWifiNetworks({ + required String deviceIdentificator, + }); Future createWifiNetwork({ - required String deviceId, + required String id, + required String deviceIdentificator, required String ssid, required String bssid, + required String password, }); Future deleteWifiNetwork({required String networkId}); diff --git a/modules/legacy/modules/settings/lib/src/features/settings/presentation/settings_screen.dart b/modules/legacy/modules/settings/lib/src/features/settings/presentation/settings_screen.dart index d56878ab..69d4156b 100644 --- a/modules/legacy/modules/settings/lib/src/features/settings/presentation/settings_screen.dart +++ b/modules/legacy/modules/settings/lib/src/features/settings/presentation/settings_screen.dart @@ -15,6 +15,12 @@ class SettingsScreen extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final theme = ref.watch(themePortProvider); final color = theme.getColorFor(ThemeCode.legacyPrimary); + final hasWifi = ref.watch( + selectedDeviceProvider.select((d) { + final types = d.value?.capabilities?.commands; + return types?.types.contains('WIFI_SEARCH') ?? false; + }), + ); return LegacyPageLayout( theme: theme, @@ -101,14 +107,15 @@ class SettingsScreen extends ConsumerWidget { text: I18n.sound, color: color, ), - // _item( - // context, - // onPressed: () => - // navigationContract.pushTo(AppRoutes.wifiSettings), - // icon: Icons.wifi_find_outlined, - // text: I18n.wifiSettings, - // color: color, - // ), + if (hasWifi) + _item( + context, + onPressed: () => + navigationContract.pushTo(AppRoutes.wifiSettings), + icon: Icons.wifi_find_outlined, + text: I18n.wifiSettings, + color: color, + ), // _item( // context, // onPressed: () => diff --git a/modules/legacy/modules/settings/lib/src/features/wifi_settings/domain/entities/scanned_wifi_network.dart b/modules/legacy/modules/settings/lib/src/features/wifi_settings/domain/entities/scanned_wifi_network.dart new file mode 100644 index 00000000..ad625d59 --- /dev/null +++ b/modules/legacy/modules/settings/lib/src/features/wifi_settings/domain/entities/scanned_wifi_network.dart @@ -0,0 +1,11 @@ +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'scanned_wifi_network.freezed.dart'; + +@freezed +abstract class ScannedWifiNetwork with _$ScannedWifiNetwork { + const factory ScannedWifiNetwork({ + required String ssid, + required String bssid, + }) = _ScannedWifiNetwork; +} diff --git a/modules/legacy/modules/settings/lib/src/features/wifi_settings/domain/entities/scanned_wifi_network.freezed.dart b/modules/legacy/modules/settings/lib/src/features/wifi_settings/domain/entities/scanned_wifi_network.freezed.dart new file mode 100644 index 00000000..0e3fc0c5 --- /dev/null +++ b/modules/legacy/modules/settings/lib/src/features/wifi_settings/domain/entities/scanned_wifi_network.freezed.dart @@ -0,0 +1,274 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND +// coverage:ignore-file +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'scanned_wifi_network.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +// dart format off +T _$identity(T value) => value; +/// @nodoc +mixin _$ScannedWifiNetwork { + + String get ssid; String get bssid; +/// Create a copy of ScannedWifiNetwork +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$ScannedWifiNetworkCopyWith get copyWith => _$ScannedWifiNetworkCopyWithImpl(this as ScannedWifiNetwork, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is ScannedWifiNetwork&&(identical(other.ssid, ssid) || other.ssid == ssid)&&(identical(other.bssid, bssid) || other.bssid == bssid)); +} + + +@override +int get hashCode => Object.hash(runtimeType,ssid,bssid); + +@override +String toString() { + return 'ScannedWifiNetwork(ssid: $ssid, bssid: $bssid)'; +} + + +} + +/// @nodoc +abstract mixin class $ScannedWifiNetworkCopyWith<$Res> { + factory $ScannedWifiNetworkCopyWith(ScannedWifiNetwork value, $Res Function(ScannedWifiNetwork) _then) = _$ScannedWifiNetworkCopyWithImpl; +@useResult +$Res call({ + String ssid, String bssid +}); + + + + +} +/// @nodoc +class _$ScannedWifiNetworkCopyWithImpl<$Res> + implements $ScannedWifiNetworkCopyWith<$Res> { + _$ScannedWifiNetworkCopyWithImpl(this._self, this._then); + + final ScannedWifiNetwork _self; + final $Res Function(ScannedWifiNetwork) _then; + +/// Create a copy of ScannedWifiNetwork +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? ssid = null,Object? bssid = null,}) { + return _then(_self.copyWith( +ssid: null == ssid ? _self.ssid : ssid // ignore: cast_nullable_to_non_nullable +as String,bssid: null == bssid ? _self.bssid : bssid // ignore: cast_nullable_to_non_nullable +as String, + )); +} + +} + + +/// Adds pattern-matching-related methods to [ScannedWifiNetwork]. +extension ScannedWifiNetworkPatterns on ScannedWifiNetwork { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _ScannedWifiNetwork value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _ScannedWifiNetwork() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _ScannedWifiNetwork value) $default,){ +final _that = this; +switch (_that) { +case _ScannedWifiNetwork(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _ScannedWifiNetwork value)? $default,){ +final _that = this; +switch (_that) { +case _ScannedWifiNetwork() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( String ssid, String bssid)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _ScannedWifiNetwork() when $default != null: +return $default(_that.ssid,_that.bssid);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( String ssid, String bssid) $default,) {final _that = this; +switch (_that) { +case _ScannedWifiNetwork(): +return $default(_that.ssid,_that.bssid);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String ssid, String bssid)? $default,) {final _that = this; +switch (_that) { +case _ScannedWifiNetwork() when $default != null: +return $default(_that.ssid,_that.bssid);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _ScannedWifiNetwork implements ScannedWifiNetwork { + const _ScannedWifiNetwork({required this.ssid, required this.bssid}); + + +@override final String ssid; +@override final String bssid; + +/// Create a copy of ScannedWifiNetwork +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$ScannedWifiNetworkCopyWith<_ScannedWifiNetwork> get copyWith => __$ScannedWifiNetworkCopyWithImpl<_ScannedWifiNetwork>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _ScannedWifiNetwork&&(identical(other.ssid, ssid) || other.ssid == ssid)&&(identical(other.bssid, bssid) || other.bssid == bssid)); +} + + +@override +int get hashCode => Object.hash(runtimeType,ssid,bssid); + +@override +String toString() { + return 'ScannedWifiNetwork(ssid: $ssid, bssid: $bssid)'; +} + + +} + +/// @nodoc +abstract mixin class _$ScannedWifiNetworkCopyWith<$Res> implements $ScannedWifiNetworkCopyWith<$Res> { + factory _$ScannedWifiNetworkCopyWith(_ScannedWifiNetwork value, $Res Function(_ScannedWifiNetwork) _then) = __$ScannedWifiNetworkCopyWithImpl; +@override @useResult +$Res call({ + String ssid, String bssid +}); + + + + +} +/// @nodoc +class __$ScannedWifiNetworkCopyWithImpl<$Res> + implements _$ScannedWifiNetworkCopyWith<$Res> { + __$ScannedWifiNetworkCopyWithImpl(this._self, this._then); + + final _ScannedWifiNetwork _self; + final $Res Function(_ScannedWifiNetwork) _then; + +/// Create a copy of ScannedWifiNetwork +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? ssid = null,Object? bssid = null,}) { + return _then(_ScannedWifiNetwork( +ssid: null == ssid ? _self.ssid : ssid // ignore: cast_nullable_to_non_nullable +as String,bssid: null == bssid ? _self.bssid : bssid // ignore: cast_nullable_to_non_nullable +as String, + )); +} + + +} + +// dart format on diff --git a/modules/legacy/modules/settings/lib/src/features/wifi_settings/domain/entities/wifi_network_entity.dart b/modules/legacy/modules/settings/lib/src/features/wifi_settings/domain/entities/wifi_network_entity.dart index f833409b..b60f49c8 100644 --- a/modules/legacy/modules/settings/lib/src/features/wifi_settings/domain/entities/wifi_network_entity.dart +++ b/modules/legacy/modules/settings/lib/src/features/wifi_settings/domain/entities/wifi_network_entity.dart @@ -8,5 +8,8 @@ abstract class WifiNetworkEntity with _$WifiNetworkEntity { required String id, required String ssid, required String bssid, + String? password, + String? deviceIdentificator, + int? createdAt, }) = _WifiNetworkEntity; } diff --git a/modules/legacy/modules/settings/lib/src/features/wifi_settings/domain/entities/wifi_network_entity.freezed.dart b/modules/legacy/modules/settings/lib/src/features/wifi_settings/domain/entities/wifi_network_entity.freezed.dart index 45c0538d..d1b4bff4 100644 --- a/modules/legacy/modules/settings/lib/src/features/wifi_settings/domain/entities/wifi_network_entity.freezed.dart +++ b/modules/legacy/modules/settings/lib/src/features/wifi_settings/domain/entities/wifi_network_entity.freezed.dart @@ -14,7 +14,7 @@ T _$identity(T value) => value; /// @nodoc mixin _$WifiNetworkEntity { - String get id; String get ssid; String get bssid; + String get id; String get ssid; String get bssid; String? get password; String? get deviceIdentificator; int? get createdAt; /// Create a copy of WifiNetworkEntity /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -25,16 +25,16 @@ $WifiNetworkEntityCopyWith get copyWith => _$WifiNetworkEntit @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is WifiNetworkEntity&&(identical(other.id, id) || other.id == id)&&(identical(other.ssid, ssid) || other.ssid == ssid)&&(identical(other.bssid, bssid) || other.bssid == bssid)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is WifiNetworkEntity&&(identical(other.id, id) || other.id == id)&&(identical(other.ssid, ssid) || other.ssid == ssid)&&(identical(other.bssid, bssid) || other.bssid == bssid)&&(identical(other.password, password) || other.password == password)&&(identical(other.deviceIdentificator, deviceIdentificator) || other.deviceIdentificator == deviceIdentificator)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)); } @override -int get hashCode => Object.hash(runtimeType,id,ssid,bssid); +int get hashCode => Object.hash(runtimeType,id,ssid,bssid,password,deviceIdentificator,createdAt); @override String toString() { - return 'WifiNetworkEntity(id: $id, ssid: $ssid, bssid: $bssid)'; + return 'WifiNetworkEntity(id: $id, ssid: $ssid, bssid: $bssid, password: $password, deviceIdentificator: $deviceIdentificator, createdAt: $createdAt)'; } @@ -45,7 +45,7 @@ abstract mixin class $WifiNetworkEntityCopyWith<$Res> { factory $WifiNetworkEntityCopyWith(WifiNetworkEntity value, $Res Function(WifiNetworkEntity) _then) = _$WifiNetworkEntityCopyWithImpl; @useResult $Res call({ - String id, String ssid, String bssid + String id, String ssid, String bssid, String? password, String? deviceIdentificator, int? createdAt }); @@ -62,12 +62,15 @@ class _$WifiNetworkEntityCopyWithImpl<$Res> /// Create a copy of WifiNetworkEntity /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? ssid = null,Object? bssid = null,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? ssid = null,Object? bssid = null,Object? password = freezed,Object? deviceIdentificator = freezed,Object? createdAt = freezed,}) { return _then(_self.copyWith( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,ssid: null == ssid ? _self.ssid : ssid // ignore: cast_nullable_to_non_nullable as String,bssid: null == bssid ? _self.bssid : bssid // ignore: cast_nullable_to_non_nullable -as String, +as String,password: freezed == password ? _self.password : password // ignore: cast_nullable_to_non_nullable +as String?,deviceIdentificator: freezed == deviceIdentificator ? _self.deviceIdentificator : deviceIdentificator // ignore: cast_nullable_to_non_nullable +as String?,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as int?, )); } @@ -152,10 +155,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String ssid, String bssid)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( String id, String ssid, String bssid, String? password, String? deviceIdentificator, int? createdAt)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _WifiNetworkEntity() when $default != null: -return $default(_that.id,_that.ssid,_that.bssid);case _: +return $default(_that.id,_that.ssid,_that.bssid,_that.password,_that.deviceIdentificator,_that.createdAt);case _: return orElse(); } @@ -173,10 +176,10 @@ return $default(_that.id,_that.ssid,_that.bssid);case _: /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( String id, String ssid, String bssid) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( String id, String ssid, String bssid, String? password, String? deviceIdentificator, int? createdAt) $default,) {final _that = this; switch (_that) { case _WifiNetworkEntity(): -return $default(_that.id,_that.ssid,_that.bssid);case _: +return $default(_that.id,_that.ssid,_that.bssid,_that.password,_that.deviceIdentificator,_that.createdAt);case _: throw StateError('Unexpected subclass'); } @@ -193,10 +196,10 @@ return $default(_that.id,_that.ssid,_that.bssid);case _: /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String ssid, String bssid)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String id, String ssid, String bssid, String? password, String? deviceIdentificator, int? createdAt)? $default,) {final _that = this; switch (_that) { case _WifiNetworkEntity() when $default != null: -return $default(_that.id,_that.ssid,_that.bssid);case _: +return $default(_that.id,_that.ssid,_that.bssid,_that.password,_that.deviceIdentificator,_that.createdAt);case _: return null; } @@ -208,12 +211,15 @@ return $default(_that.id,_that.ssid,_that.bssid);case _: class _WifiNetworkEntity implements WifiNetworkEntity { - const _WifiNetworkEntity({required this.id, required this.ssid, required this.bssid}); + const _WifiNetworkEntity({required this.id, required this.ssid, required this.bssid, this.password, this.deviceIdentificator, this.createdAt}); @override final String id; @override final String ssid; @override final String bssid; +@override final String? password; +@override final String? deviceIdentificator; +@override final int? createdAt; /// Create a copy of WifiNetworkEntity /// with the given fields replaced by the non-null parameter values. @@ -225,16 +231,16 @@ _$WifiNetworkEntityCopyWith<_WifiNetworkEntity> get copyWith => __$WifiNetworkEn @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _WifiNetworkEntity&&(identical(other.id, id) || other.id == id)&&(identical(other.ssid, ssid) || other.ssid == ssid)&&(identical(other.bssid, bssid) || other.bssid == bssid)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _WifiNetworkEntity&&(identical(other.id, id) || other.id == id)&&(identical(other.ssid, ssid) || other.ssid == ssid)&&(identical(other.bssid, bssid) || other.bssid == bssid)&&(identical(other.password, password) || other.password == password)&&(identical(other.deviceIdentificator, deviceIdentificator) || other.deviceIdentificator == deviceIdentificator)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)); } @override -int get hashCode => Object.hash(runtimeType,id,ssid,bssid); +int get hashCode => Object.hash(runtimeType,id,ssid,bssid,password,deviceIdentificator,createdAt); @override String toString() { - return 'WifiNetworkEntity(id: $id, ssid: $ssid, bssid: $bssid)'; + return 'WifiNetworkEntity(id: $id, ssid: $ssid, bssid: $bssid, password: $password, deviceIdentificator: $deviceIdentificator, createdAt: $createdAt)'; } @@ -245,7 +251,7 @@ abstract mixin class _$WifiNetworkEntityCopyWith<$Res> implements $WifiNetworkEn factory _$WifiNetworkEntityCopyWith(_WifiNetworkEntity value, $Res Function(_WifiNetworkEntity) _then) = __$WifiNetworkEntityCopyWithImpl; @override @useResult $Res call({ - String id, String ssid, String bssid + String id, String ssid, String bssid, String? password, String? deviceIdentificator, int? createdAt }); @@ -262,12 +268,15 @@ class __$WifiNetworkEntityCopyWithImpl<$Res> /// Create a copy of WifiNetworkEntity /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? ssid = null,Object? bssid = null,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? ssid = null,Object? bssid = null,Object? password = freezed,Object? deviceIdentificator = freezed,Object? createdAt = freezed,}) { return _then(_WifiNetworkEntity( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as String,ssid: null == ssid ? _self.ssid : ssid // ignore: cast_nullable_to_non_nullable as String,bssid: null == bssid ? _self.bssid : bssid // ignore: cast_nullable_to_non_nullable -as String, +as String,password: freezed == password ? _self.password : password // ignore: cast_nullable_to_non_nullable +as String?,deviceIdentificator: freezed == deviceIdentificator ? _self.deviceIdentificator : deviceIdentificator // ignore: cast_nullable_to_non_nullable +as String?,createdAt: freezed == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable +as int?, )); } diff --git a/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/state/wifi_settings_view_model.dart b/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/state/wifi_settings_view_model.dart index 77af60a3..482dc99c 100644 --- a/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/state/wifi_settings_view_model.dart +++ b/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/state/wifi_settings_view_model.dart @@ -1,12 +1,16 @@ import 'dart:async'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:get_it/get_it.dart'; import 'package:legacy_shared/legacy_shared.dart'; -import 'package:sf_localizations/sf_localizations.dart'; +import 'package:sf_infrastructure/sf_infrastructure.dart'; import 'package:sf_tracking/sf_tracking.dart'; +import 'package:uuid/uuid.dart'; import '../../../../core/domain/repositories/wifi_repository.dart'; import '../../../../core/providers/wifi_repository_provider.dart'; +import '../../domain/entities/scanned_wifi_network.dart'; +import '../../domain/entities/wifi_network_entity.dart'; import 'wifi_settings_view_state.dart'; final wifiSettingsViewModelProvider = @@ -16,90 +20,260 @@ final wifiSettingsViewModelProvider = class WifiSettingsViewModel extends Notifier { late final WifiRepository _repository; + late final CommandsRepository _commands; late final SfTrackingRepository _tracking; + late final WebSocketService _webSocket; + StreamSubscription? _webSocketSubscription; + Timer? _scanCountdown; + Timer? _currentNetworkTimeout; + + static const _scanDurationSeconds = 30; @override WifiSettingsViewState build() { _repository = ref.read(wifiRepositoryProvider); + _commands = ref.read(commandsRepositoryProvider); _tracking = ref.read(sfTrackingProvider); + _webSocket = GetIt.I(); + + _webSocketSubscription = _webSocket.events.listen(_onWebSocketEvent); + ref.onDispose(() { + _webSocketSubscription?.cancel(); + _scanCountdown?.cancel(); + _currentNetworkTimeout?.cancel(); + }); + Future.microtask(_load); return const WifiSettingsViewState(); } - Future _load() async { - try { - final device = ref.read(selectedDeviceProvider).value; - if (device == null) return; + String? get _identificator => + ref.read(selectedDeviceProvider).value?.identificator; - final networks = await _repository.getWifiNetworks(deviceId: device.id); - state = state.copyWith(networks: networks, isLoading: false); - } catch (e) { + void _onWebSocketEvent(WebSocketEvent event) { + switch (event) { + case WifiEvent(): + _currentNetworkTimeout?.cancel(); + final network = WifiNetworkEntity( + id: '', + ssid: event.ssid, + bssid: event.bssid, + password: event.password, + ); + state = state.copyWith( + currentNetwork: network, + isConnecting: false, + isLoadingCurrentNetwork: false, + ); + case WifiSearchEvent(): + _scanCountdown?.cancel(); + final networks = event.wifis + .map( + (wifi) => ScannedWifiNetwork( + ssid: wifi['ssid'] as String? ?? '', + bssid: wifi['bssid'] as String? ?? '', + ), + ) + .where((network) => network.ssid.isNotEmpty) + .toList(); + state = state.copyWith( + availableNetworks: networks, + isScanning: false, + scanSecondsRemaining: 0, + ); + default: + break; + } + } + + Future _load() async { + final identificator = _identificator; + if (identificator == null) { + state = state.copyWith(isLoading: false); + return; + } + + try { + final networks = await _repository.getWifiNetworks( + deviceIdentificator: identificator, + ); + if (!ref.mounted) return; + + state = state.copyWith( + savedNetworks: networks, + isLoading: false, + isLoadingCurrentNetwork: true, + ); + + unawaited( + _commands + .send( + request: SendCommandRequestModel( + device: identificator, + command: DeviceCommand.wifiCurrent, + ), + ) + .catchError((_) { + if (ref.mounted) { + state = state.copyWith(isLoadingCurrentNetwork: false); + } + }), + ); + + _currentNetworkTimeout?.cancel(); + _currentNetworkTimeout = Timer(const Duration(seconds: 15), () { + if (!ref.mounted) return; + if (state.isLoadingCurrentNetwork) { + state = state.copyWith(isLoadingCurrentNetwork: false); + } + }); + } catch (_) { + if (!ref.mounted) return; state = state.copyWith( isLoading: false, - errorMessage: formatErrorMessage(e), + error: WifiSettingsError.loadFailed, ); } } - Future addNetwork({required String ssid, required String bssid}) async { - state = state.copyWith(isSaving: true, errorMessage: ''); + Future scanNetworks() async { + final identificator = _identificator; + if (identificator == null) return; + + state = state.copyWith( + isScanning: true, + scanSecondsRemaining: _scanDurationSeconds, + error: null, + ); try { - final device = ref.read(selectedDeviceProvider).value; - if (device == null) return; - - await _repository.createWifiNetwork( - deviceId: device.id, - ssid: ssid, - bssid: bssid, + await _commands.send( + request: SendCommandRequestModel( + device: identificator, + command: DeviceCommand.wifiSearch, + ), ); - final networks = await _repository.getWifiNetworks(deviceId: device.id); + _scanCountdown?.cancel(); + + _scanCountdown = Timer.periodic(const Duration(seconds: 1), (_) { + if (!ref.mounted) { + _scanCountdown?.cancel(); + return; + } + final remaining = state.scanSecondsRemaining - 1; + if (remaining <= 0) { + _scanCountdown?.cancel(); + if (state.isScanning) { + state = state.copyWith( + isScanning: false, + scanSecondsRemaining: 0, + error: WifiSettingsError.scanFailed, + ); + } + } else { + state = state.copyWith(scanSecondsRemaining: remaining); + } + }); + } catch (_) { + if (!ref.mounted) return; + _scanCountdown?.cancel(); + state = state.copyWith( + isScanning: false, + scanSecondsRemaining: 0, + error: WifiSettingsError.scanFailed, + ); + } + } + + Future connectAndSave({ + required String ssid, + required String bssid, + required String password, + }) async { + final identificator = _identificator; + if (identificator == null) return; + + state = state.copyWith(isConnecting: true, error: null, success: null); + + try { + await _commands.send( + request: SendCommandRequestModel( + device: identificator, + command: DeviceCommand.setWifi, + data: {'ssid': ssid, 'bssid': bssid, 'password': password}, + ), + ); + + final id = const Uuid().v4(); + await _repository.createWifiNetwork( + id: id, + deviceIdentificator: identificator, + ssid: ssid, + bssid: bssid, + password: password, + ); + if (!ref.mounted) return; + + final networks = await _repository.getWifiNetworks( + deviceIdentificator: identificator, + ); + if (!ref.mounted) return; unawaited(_tracking.legacySettingsWifiAdded(totalCount: networks.length)); state = state.copyWith( - networks: networks, - isSaving: false, - successMessage: I18n.wifiNetworkAdded, + savedNetworks: networks, + isConnecting: false, + success: WifiSettingsSuccess.networkSaved, ); - } catch (e) { + } catch (_) { + if (!ref.mounted) return; state = state.copyWith( - isSaving: false, - errorMessage: formatErrorMessage(e), + isConnecting: false, + error: WifiSettingsError.saveFailed, ); } } Future removeNetwork(String networkId) async { - state = state.copyWith(isSaving: true, errorMessage: ''); + final identificator = _identificator; + if (identificator == null) return; + + state = state.copyWith(isSaving: true, error: null, success: null); try { - final device = ref.read(selectedDeviceProvider).value; - if (device == null) return; - await _repository.deleteWifiNetwork(networkId: networkId); + if (!ref.mounted) return; - final networks = await _repository.getWifiNetworks(deviceId: device.id); + final networks = await _repository.getWifiNetworks( + deviceIdentificator: identificator, + ); + if (!ref.mounted) return; unawaited( _tracking.legacySettingsWifiRemoved(totalCount: networks.length), ); state = state.copyWith( - networks: networks, + savedNetworks: networks, isSaving: false, - successMessage: I18n.wifiNetworkRemoved, + success: WifiSettingsSuccess.networkDeleted, ); - } catch (e) { + } catch (_) { + if (!ref.mounted) return; state = state.copyWith( isSaving: false, - errorMessage: formatErrorMessage(e), + error: WifiSettingsError.deleteFailed, ); } } + void clearError() { + if (state.error != null) state = state.copyWith(error: null); + } + void clearSuccess() { - state = state.copyWith(successMessage: ''); + if (state.success != null) state = state.copyWith(success: null); } } diff --git a/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/state/wifi_settings_view_state.dart b/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/state/wifi_settings_view_state.dart index 0d9ecec5..2ba51697 100644 --- a/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/state/wifi_settings_view_state.dart +++ b/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/state/wifi_settings_view_state.dart @@ -1,16 +1,27 @@ import 'package:freezed_annotation/freezed_annotation.dart'; +import '../../domain/entities/scanned_wifi_network.dart'; import '../../domain/entities/wifi_network_entity.dart'; part 'wifi_settings_view_state.freezed.dart'; +enum WifiSettingsError { loadFailed, scanFailed, connectFailed, saveFailed, deleteFailed } + +enum WifiSettingsSuccess { networkSaved, networkDeleted, connected } + @freezed abstract class WifiSettingsViewState with _$WifiSettingsViewState { const factory WifiSettingsViewState({ - @Default([]) List networks, + @Default([]) List savedNetworks, + @Default([]) List availableNetworks, + WifiNetworkEntity? currentNetwork, @Default(true) bool isLoading, + @Default(false) bool isLoadingCurrentNetwork, + @Default(false) bool isScanning, + @Default(0) int scanSecondsRemaining, @Default(false) bool isSaving, - @Default('') String successMessage, - @Default('') String errorMessage, + @Default(false) bool isConnecting, + WifiSettingsError? error, + WifiSettingsSuccess? success, }) = _WifiSettingsViewState; } diff --git a/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/state/wifi_settings_view_state.freezed.dart b/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/state/wifi_settings_view_state.freezed.dart index 74aaf812..a2d87630 100644 --- a/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/state/wifi_settings_view_state.freezed.dart +++ b/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/state/wifi_settings_view_state.freezed.dart @@ -14,7 +14,7 @@ T _$identity(T value) => value; /// @nodoc mixin _$WifiSettingsViewState { - List get networks; bool get isLoading; bool get isSaving; String get successMessage; String get errorMessage; + List get savedNetworks; List get availableNetworks; WifiNetworkEntity? get currentNetwork; bool get isLoading; bool get isLoadingCurrentNetwork; bool get isScanning; int get scanSecondsRemaining; bool get isSaving; bool get isConnecting; WifiSettingsError? get error; WifiSettingsSuccess? get success; /// Create a copy of WifiSettingsViewState /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -25,16 +25,16 @@ $WifiSettingsViewStateCopyWith get copyWith => _$WifiSett @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is WifiSettingsViewState&&const DeepCollectionEquality().equals(other.networks, networks)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isSaving, isSaving) || other.isSaving == isSaving)&&(identical(other.successMessage, successMessage) || other.successMessage == successMessage)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is WifiSettingsViewState&&const DeepCollectionEquality().equals(other.savedNetworks, savedNetworks)&&const DeepCollectionEquality().equals(other.availableNetworks, availableNetworks)&&(identical(other.currentNetwork, currentNetwork) || other.currentNetwork == currentNetwork)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isLoadingCurrentNetwork, isLoadingCurrentNetwork) || other.isLoadingCurrentNetwork == isLoadingCurrentNetwork)&&(identical(other.isScanning, isScanning) || other.isScanning == isScanning)&&(identical(other.scanSecondsRemaining, scanSecondsRemaining) || other.scanSecondsRemaining == scanSecondsRemaining)&&(identical(other.isSaving, isSaving) || other.isSaving == isSaving)&&(identical(other.isConnecting, isConnecting) || other.isConnecting == isConnecting)&&(identical(other.error, error) || other.error == error)&&(identical(other.success, success) || other.success == success)); } @override -int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(networks),isLoading,isSaving,successMessage,errorMessage); +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(savedNetworks),const DeepCollectionEquality().hash(availableNetworks),currentNetwork,isLoading,isLoadingCurrentNetwork,isScanning,scanSecondsRemaining,isSaving,isConnecting,error,success); @override String toString() { - return 'WifiSettingsViewState(networks: $networks, isLoading: $isLoading, isSaving: $isSaving, successMessage: $successMessage, errorMessage: $errorMessage)'; + return 'WifiSettingsViewState(savedNetworks: $savedNetworks, availableNetworks: $availableNetworks, currentNetwork: $currentNetwork, isLoading: $isLoading, isLoadingCurrentNetwork: $isLoadingCurrentNetwork, isScanning: $isScanning, scanSecondsRemaining: $scanSecondsRemaining, isSaving: $isSaving, isConnecting: $isConnecting, error: $error, success: $success)'; } @@ -45,11 +45,11 @@ abstract mixin class $WifiSettingsViewStateCopyWith<$Res> { factory $WifiSettingsViewStateCopyWith(WifiSettingsViewState value, $Res Function(WifiSettingsViewState) _then) = _$WifiSettingsViewStateCopyWithImpl; @useResult $Res call({ - List networks, bool isLoading, bool isSaving, String successMessage, String errorMessage + List savedNetworks, List availableNetworks, WifiNetworkEntity? currentNetwork, bool isLoading, bool isLoadingCurrentNetwork, bool isScanning, int scanSecondsRemaining, bool isSaving, bool isConnecting, WifiSettingsError? error, WifiSettingsSuccess? success }); - +$WifiNetworkEntityCopyWith<$Res>? get currentNetwork; } /// @nodoc @@ -62,17 +62,35 @@ class _$WifiSettingsViewStateCopyWithImpl<$Res> /// Create a copy of WifiSettingsViewState /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? networks = null,Object? isLoading = null,Object? isSaving = null,Object? successMessage = null,Object? errorMessage = null,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? savedNetworks = null,Object? availableNetworks = null,Object? currentNetwork = freezed,Object? isLoading = null,Object? isLoadingCurrentNetwork = null,Object? isScanning = null,Object? scanSecondsRemaining = null,Object? isSaving = null,Object? isConnecting = null,Object? error = freezed,Object? success = freezed,}) { return _then(_self.copyWith( -networks: null == networks ? _self.networks : networks // ignore: cast_nullable_to_non_nullable -as List,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable -as bool,isSaving: null == isSaving ? _self.isSaving : isSaving // ignore: cast_nullable_to_non_nullable -as bool,successMessage: null == successMessage ? _self.successMessage : successMessage // ignore: cast_nullable_to_non_nullable -as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable -as String, +savedNetworks: null == savedNetworks ? _self.savedNetworks : savedNetworks // ignore: cast_nullable_to_non_nullable +as List,availableNetworks: null == availableNetworks ? _self.availableNetworks : availableNetworks // ignore: cast_nullable_to_non_nullable +as List,currentNetwork: freezed == currentNetwork ? _self.currentNetwork : currentNetwork // ignore: cast_nullable_to_non_nullable +as WifiNetworkEntity?,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable +as bool,isLoadingCurrentNetwork: null == isLoadingCurrentNetwork ? _self.isLoadingCurrentNetwork : isLoadingCurrentNetwork // ignore: cast_nullable_to_non_nullable +as bool,isScanning: null == isScanning ? _self.isScanning : isScanning // ignore: cast_nullable_to_non_nullable +as bool,scanSecondsRemaining: null == scanSecondsRemaining ? _self.scanSecondsRemaining : scanSecondsRemaining // ignore: cast_nullable_to_non_nullable +as int,isSaving: null == isSaving ? _self.isSaving : isSaving // ignore: cast_nullable_to_non_nullable +as bool,isConnecting: null == isConnecting ? _self.isConnecting : isConnecting // ignore: cast_nullable_to_non_nullable +as bool,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable +as WifiSettingsError?,success: freezed == success ? _self.success : success // ignore: cast_nullable_to_non_nullable +as WifiSettingsSuccess?, )); } +/// Create a copy of WifiSettingsViewState +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$WifiNetworkEntityCopyWith<$Res>? get currentNetwork { + if (_self.currentNetwork == null) { + return null; + } + return $WifiNetworkEntityCopyWith<$Res>(_self.currentNetwork!, (value) { + return _then(_self.copyWith(currentNetwork: value)); + }); +} } @@ -154,10 +172,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( List networks, bool isLoading, bool isSaving, String successMessage, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( List savedNetworks, List availableNetworks, WifiNetworkEntity? currentNetwork, bool isLoading, bool isLoadingCurrentNetwork, bool isScanning, int scanSecondsRemaining, bool isSaving, bool isConnecting, WifiSettingsError? error, WifiSettingsSuccess? success)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _WifiSettingsViewState() when $default != null: -return $default(_that.networks,_that.isLoading,_that.isSaving,_that.successMessage,_that.errorMessage);case _: +return $default(_that.savedNetworks,_that.availableNetworks,_that.currentNetwork,_that.isLoading,_that.isLoadingCurrentNetwork,_that.isScanning,_that.scanSecondsRemaining,_that.isSaving,_that.isConnecting,_that.error,_that.success);case _: return orElse(); } @@ -175,10 +193,10 @@ return $default(_that.networks,_that.isLoading,_that.isSaving,_that.successMessa /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( List networks, bool isLoading, bool isSaving, String successMessage, String errorMessage) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( List savedNetworks, List availableNetworks, WifiNetworkEntity? currentNetwork, bool isLoading, bool isLoadingCurrentNetwork, bool isScanning, int scanSecondsRemaining, bool isSaving, bool isConnecting, WifiSettingsError? error, WifiSettingsSuccess? success) $default,) {final _that = this; switch (_that) { case _WifiSettingsViewState(): -return $default(_that.networks,_that.isLoading,_that.isSaving,_that.successMessage,_that.errorMessage);case _: +return $default(_that.savedNetworks,_that.availableNetworks,_that.currentNetwork,_that.isLoading,_that.isLoadingCurrentNetwork,_that.isScanning,_that.scanSecondsRemaining,_that.isSaving,_that.isConnecting,_that.error,_that.success);case _: throw StateError('Unexpected subclass'); } @@ -195,10 +213,10 @@ return $default(_that.networks,_that.isLoading,_that.isSaving,_that.successMessa /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( List networks, bool isLoading, bool isSaving, String successMessage, String errorMessage)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( List savedNetworks, List availableNetworks, WifiNetworkEntity? currentNetwork, bool isLoading, bool isLoadingCurrentNetwork, bool isScanning, int scanSecondsRemaining, bool isSaving, bool isConnecting, WifiSettingsError? error, WifiSettingsSuccess? success)? $default,) {final _that = this; switch (_that) { case _WifiSettingsViewState() when $default != null: -return $default(_that.networks,_that.isLoading,_that.isSaving,_that.successMessage,_that.errorMessage);case _: +return $default(_that.savedNetworks,_that.availableNetworks,_that.currentNetwork,_that.isLoading,_that.isLoadingCurrentNetwork,_that.isScanning,_that.scanSecondsRemaining,_that.isSaving,_that.isConnecting,_that.error,_that.success);case _: return null; } @@ -210,20 +228,32 @@ return $default(_that.networks,_that.isLoading,_that.isSaving,_that.successMessa class _WifiSettingsViewState implements WifiSettingsViewState { - const _WifiSettingsViewState({final List networks = const [], this.isLoading = true, this.isSaving = false, this.successMessage = '', this.errorMessage = ''}): _networks = networks; + const _WifiSettingsViewState({final List savedNetworks = const [], final List availableNetworks = const [], this.currentNetwork, this.isLoading = true, this.isLoadingCurrentNetwork = false, this.isScanning = false, this.scanSecondsRemaining = 0, this.isSaving = false, this.isConnecting = false, this.error, this.success}): _savedNetworks = savedNetworks,_availableNetworks = availableNetworks; - final List _networks; -@override@JsonKey() List get networks { - if (_networks is EqualUnmodifiableListView) return _networks; + final List _savedNetworks; +@override@JsonKey() List get savedNetworks { + if (_savedNetworks is EqualUnmodifiableListView) return _savedNetworks; // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_networks); + return EqualUnmodifiableListView(_savedNetworks); } + final List _availableNetworks; +@override@JsonKey() List get availableNetworks { + if (_availableNetworks is EqualUnmodifiableListView) return _availableNetworks; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_availableNetworks); +} + +@override final WifiNetworkEntity? currentNetwork; @override@JsonKey() final bool isLoading; +@override@JsonKey() final bool isLoadingCurrentNetwork; +@override@JsonKey() final bool isScanning; +@override@JsonKey() final int scanSecondsRemaining; @override@JsonKey() final bool isSaving; -@override@JsonKey() final String successMessage; -@override@JsonKey() final String errorMessage; +@override@JsonKey() final bool isConnecting; +@override final WifiSettingsError? error; +@override final WifiSettingsSuccess? success; /// Create a copy of WifiSettingsViewState /// with the given fields replaced by the non-null parameter values. @@ -235,16 +265,16 @@ _$WifiSettingsViewStateCopyWith<_WifiSettingsViewState> get copyWith => __$WifiS @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _WifiSettingsViewState&&const DeepCollectionEquality().equals(other._networks, _networks)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isSaving, isSaving) || other.isSaving == isSaving)&&(identical(other.successMessage, successMessage) || other.successMessage == successMessage)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _WifiSettingsViewState&&const DeepCollectionEquality().equals(other._savedNetworks, _savedNetworks)&&const DeepCollectionEquality().equals(other._availableNetworks, _availableNetworks)&&(identical(other.currentNetwork, currentNetwork) || other.currentNetwork == currentNetwork)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isLoadingCurrentNetwork, isLoadingCurrentNetwork) || other.isLoadingCurrentNetwork == isLoadingCurrentNetwork)&&(identical(other.isScanning, isScanning) || other.isScanning == isScanning)&&(identical(other.scanSecondsRemaining, scanSecondsRemaining) || other.scanSecondsRemaining == scanSecondsRemaining)&&(identical(other.isSaving, isSaving) || other.isSaving == isSaving)&&(identical(other.isConnecting, isConnecting) || other.isConnecting == isConnecting)&&(identical(other.error, error) || other.error == error)&&(identical(other.success, success) || other.success == success)); } @override -int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_networks),isLoading,isSaving,successMessage,errorMessage); +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_savedNetworks),const DeepCollectionEquality().hash(_availableNetworks),currentNetwork,isLoading,isLoadingCurrentNetwork,isScanning,scanSecondsRemaining,isSaving,isConnecting,error,success); @override String toString() { - return 'WifiSettingsViewState(networks: $networks, isLoading: $isLoading, isSaving: $isSaving, successMessage: $successMessage, errorMessage: $errorMessage)'; + return 'WifiSettingsViewState(savedNetworks: $savedNetworks, availableNetworks: $availableNetworks, currentNetwork: $currentNetwork, isLoading: $isLoading, isLoadingCurrentNetwork: $isLoadingCurrentNetwork, isScanning: $isScanning, scanSecondsRemaining: $scanSecondsRemaining, isSaving: $isSaving, isConnecting: $isConnecting, error: $error, success: $success)'; } @@ -255,11 +285,11 @@ abstract mixin class _$WifiSettingsViewStateCopyWith<$Res> implements $WifiSetti factory _$WifiSettingsViewStateCopyWith(_WifiSettingsViewState value, $Res Function(_WifiSettingsViewState) _then) = __$WifiSettingsViewStateCopyWithImpl; @override @useResult $Res call({ - List networks, bool isLoading, bool isSaving, String successMessage, String errorMessage + List savedNetworks, List availableNetworks, WifiNetworkEntity? currentNetwork, bool isLoading, bool isLoadingCurrentNetwork, bool isScanning, int scanSecondsRemaining, bool isSaving, bool isConnecting, WifiSettingsError? error, WifiSettingsSuccess? success }); - +@override $WifiNetworkEntityCopyWith<$Res>? get currentNetwork; } /// @nodoc @@ -272,18 +302,36 @@ class __$WifiSettingsViewStateCopyWithImpl<$Res> /// Create a copy of WifiSettingsViewState /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? networks = null,Object? isLoading = null,Object? isSaving = null,Object? successMessage = null,Object? errorMessage = null,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? savedNetworks = null,Object? availableNetworks = null,Object? currentNetwork = freezed,Object? isLoading = null,Object? isLoadingCurrentNetwork = null,Object? isScanning = null,Object? scanSecondsRemaining = null,Object? isSaving = null,Object? isConnecting = null,Object? error = freezed,Object? success = freezed,}) { return _then(_WifiSettingsViewState( -networks: null == networks ? _self._networks : networks // ignore: cast_nullable_to_non_nullable -as List,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable -as bool,isSaving: null == isSaving ? _self.isSaving : isSaving // ignore: cast_nullable_to_non_nullable -as bool,successMessage: null == successMessage ? _self.successMessage : successMessage // ignore: cast_nullable_to_non_nullable -as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable -as String, +savedNetworks: null == savedNetworks ? _self._savedNetworks : savedNetworks // ignore: cast_nullable_to_non_nullable +as List,availableNetworks: null == availableNetworks ? _self._availableNetworks : availableNetworks // ignore: cast_nullable_to_non_nullable +as List,currentNetwork: freezed == currentNetwork ? _self.currentNetwork : currentNetwork // ignore: cast_nullable_to_non_nullable +as WifiNetworkEntity?,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable +as bool,isLoadingCurrentNetwork: null == isLoadingCurrentNetwork ? _self.isLoadingCurrentNetwork : isLoadingCurrentNetwork // ignore: cast_nullable_to_non_nullable +as bool,isScanning: null == isScanning ? _self.isScanning : isScanning // ignore: cast_nullable_to_non_nullable +as bool,scanSecondsRemaining: null == scanSecondsRemaining ? _self.scanSecondsRemaining : scanSecondsRemaining // ignore: cast_nullable_to_non_nullable +as int,isSaving: null == isSaving ? _self.isSaving : isSaving // ignore: cast_nullable_to_non_nullable +as bool,isConnecting: null == isConnecting ? _self.isConnecting : isConnecting // ignore: cast_nullable_to_non_nullable +as bool,error: freezed == error ? _self.error : error // ignore: cast_nullable_to_non_nullable +as WifiSettingsError?,success: freezed == success ? _self.success : success // ignore: cast_nullable_to_non_nullable +as WifiSettingsSuccess?, )); } +/// Create a copy of WifiSettingsViewState +/// with the given fields replaced by the non-null parameter values. +@override +@pragma('vm:prefer-inline') +$WifiNetworkEntityCopyWith<$Res>? get currentNetwork { + if (_self.currentNetwork == null) { + return null; + } + return $WifiNetworkEntityCopyWith<$Res>(_self.currentNetwork!, (value) { + return _then(_self.copyWith(currentNetwork: value)); + }); +} } // dart format on diff --git a/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/widgets/add_wifi_network_sheet.dart b/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/widgets/add_wifi_network_sheet.dart index 2c67bbd8..c668f109 100644 --- a/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/widgets/add_wifi_network_sheet.dart +++ b/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/widgets/add_wifi_network_sheet.dart @@ -6,45 +6,63 @@ import 'package:utils/utils.dart'; import '../state/wifi_settings_view_model.dart'; -void showAddWifiNetworkSheet(BuildContext context) { +void showConnectWifiSheet( + BuildContext context, { + String? ssid, + String? bssid, +}) { showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, - builder: (_) => const _AddWifiNetworkSheet(), + builder: (_) => _ConnectWifiSheet(ssid: ssid, bssid: bssid), ); } -class _AddWifiNetworkSheet extends ConsumerStatefulWidget { - const _AddWifiNetworkSheet(); +class _ConnectWifiSheet extends ConsumerStatefulWidget { + final String? ssid; + final String? bssid; + + const _ConnectWifiSheet({this.ssid, this.bssid}); @override - ConsumerState<_AddWifiNetworkSheet> createState() => - _AddWifiNetworkSheetState(); + ConsumerState<_ConnectWifiSheet> createState() => _ConnectWifiSheetState(); } -class _AddWifiNetworkSheetState extends ConsumerState<_AddWifiNetworkSheet> { - final _ssidController = TextEditingController(); - final _bssidController = TextEditingController(); +class _ConnectWifiSheetState extends ConsumerState<_ConnectWifiSheet> { + late final TextEditingController _ssidController; + late final TextEditingController _bssidController; + final _passwordController = TextEditingController(); + bool _obscurePassword = true; + + @override + void initState() { + super.initState(); + _ssidController = TextEditingController(text: widget.ssid ?? ''); + _bssidController = TextEditingController(text: widget.bssid ?? ''); + } @override void dispose() { _ssidController.dispose(); _bssidController.dispose(); + _passwordController.dispose(); super.dispose(); } bool get _canSave => _ssidController.text.trim().isNotEmpty && - _bssidController.text.trim().isNotEmpty; + _bssidController.text.trim().isNotEmpty && + _passwordController.text.trim().isNotEmpty; void _submit() { if (!_canSave) return; final vm = ref.read(wifiSettingsViewModelProvider.notifier); - vm.addNetwork( + vm.connectAndSave( ssid: _ssidController.text.trim(), bssid: _bssidController.text.trim(), + password: _passwordController.text.trim(), ); Navigator.pop(context); } @@ -53,10 +71,11 @@ class _AddWifiNetworkSheetState extends ConsumerState<_AddWifiNetworkSheet> { Widget build(BuildContext context) { final theme = ref.watch(themePortProvider); final primaryColor = theme.getColorFor(ThemeCode.legacyPrimary); - final isSaving = ref.watch( - wifiSettingsViewModelProvider.select((s) => s.isSaving), + final isConnecting = ref.watch( + wifiSettingsViewModelProvider.select((s) => s.isConnecting), ); final bottomInset = MediaQuery.of(context).viewInsets.bottom; + final hasPrefilled = widget.ssid != null; return Padding( padding: EdgeInsets.only(bottom: bottomInset), @@ -91,7 +110,9 @@ class _AddWifiNetworkSheetState extends ConsumerState<_AddWifiNetworkSheet> { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - context.translate(I18n.addWifiNetwork), + hasPrefilled + ? context.translate(I18n.wifiConnectToNetwork) + : context.translate(I18n.addWifiNetwork), style: TextStyle( fontSize: SizeUtils.getByScreen(small: 20, big: 21), fontWeight: FontWeight.w600, @@ -99,11 +120,12 @@ class _AddWifiNetworkSheetState extends ConsumerState<_AddWifiNetworkSheet> { ), ), TextButton( - onPressed: _canSave && !isSaving ? _submit : null, - child: isSaving + onPressed: _canSave && !isConnecting ? _submit : null, + child: isConnecting ? SizedBox( width: SizeUtils.getByScreen(small: 20, big: 22), - height: SizeUtils.getByScreen(small: 20, big: 22), + height: + SizeUtils.getByScreen(small: 20, big: 22), child: CircularProgressIndicator( strokeWidth: 2, color: primaryColor, @@ -134,6 +156,7 @@ class _AddWifiNetworkSheetState extends ConsumerState<_AddWifiNetworkSheet> { SizedBox(height: 8), TextField( controller: _ssidController, + readOnly: hasPrefilled, onChanged: (_) => setState(() {}), decoration: _inputDecoration( hintText: context.translate(I18n.wifiSsidHint), @@ -151,6 +174,7 @@ class _AddWifiNetworkSheetState extends ConsumerState<_AddWifiNetworkSheet> { SizedBox(height: 8), TextField( controller: _bssidController, + readOnly: hasPrefilled, onChanged: (_) => setState(() {}), decoration: _inputDecoration( hintText: context.translate(I18n.wifiBssidHint), @@ -158,6 +182,36 @@ class _AddWifiNetworkSheetState extends ConsumerState<_AddWifiNetworkSheet> { ), ), SizedBox(height: SizeUtils.getByScreen(small: 16, big: 18)), + Text( + context.translate(I18n.wifiPassword), + style: TextStyle( + fontSize: SizeUtils.getByScreen(small: 15, big: 16), + fontWeight: FontWeight.w500, + ), + ), + SizedBox(height: 8), + TextField( + controller: _passwordController, + obscureText: _obscurePassword, + onChanged: (_) => setState(() {}), + decoration: _inputDecoration( + hintText: context.translate(I18n.wifiPasswordHint), + primaryColor: primaryColor, + ).copyWith( + suffixIcon: IconButton( + onPressed: () => + setState(() => _obscurePassword = !_obscurePassword), + icon: Icon( + _obscurePassword + ? Icons.visibility_off + : Icons.visibility, + color: Colors.grey, + size: SizeUtils.getByScreen(small: 22, big: 24), + ), + ), + ), + ), + SizedBox(height: SizeUtils.getByScreen(small: 16, big: 18)), ], ), ), diff --git a/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/widgets/available_wifi_network_card.dart b/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/widgets/available_wifi_network_card.dart new file mode 100644 index 00000000..330e95d6 --- /dev/null +++ b/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/widgets/available_wifi_network_card.dart @@ -0,0 +1,84 @@ +import 'package:design_system/design_system.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:utils/utils.dart'; + +import '../../domain/entities/scanned_wifi_network.dart'; + +class AvailableWifiNetworkCard extends ConsumerWidget { + final ScannedWifiNetwork network; + final VoidCallback onTap; + + const AvailableWifiNetworkCard({ + super.key, + required this.network, + required this.onTap, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final theme = ref.watch(themePortProvider); + final primaryColor = theme.getColorFor(ThemeCode.legacyPrimary); + + return Padding( + padding: EdgeInsets.only( + bottom: SizeUtils.getByScreen(small: 10, big: 8), + ), + child: GestureDetector( + onTap: onTap, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: SizeUtils.getByScreen(small: 16, big: 14), + vertical: SizeUtils.getByScreen(small: 14, big: 12), + ), + decoration: BoxDecoration( + color: theme.getColorFor(ThemeCode.backgroundSecondary), + borderRadius: BorderRadius.all(Radius.circular(16)), + ), + child: Row( + children: [ + Icon( + Icons.wifi, + color: primaryColor, + size: SizeUtils.getByScreen(small: 28, big: 30), + ), + SizedBox(width: SizeUtils.getByScreen(small: 12, big: 14)), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + network.ssid, + style: TextStyle( + fontWeight: FontWeight.w600, + color: theme.getColorFor(ThemeCode.textPrimary), + fontSize: SizeUtils.getByScreen(small: 15, big: 16), + ), + ), + SizedBox(height: 2), + Text( + network.bssid, + style: TextStyle( + color: theme + .getColorFor(ThemeCode.textPrimary) + .withAlpha(178), + fontSize: SizeUtils.getByScreen(small: 13, big: 14), + ), + ), + ], + ), + ), + Icon( + Icons.chevron_right, + color: theme + .getColorFor(ThemeCode.textPrimary) + .withAlpha(178), + size: SizeUtils.getByScreen(small: 24, big: 26), + ), + ], + ), + ), + ), + ); + } +} diff --git a/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/wifi_settings_screen.dart b/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/wifi_settings_screen.dart index 9f4eab50..4c9821a2 100644 --- a/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/wifi_settings_screen.dart +++ b/modules/legacy/modules/settings/lib/src/features/wifi_settings/presentation/wifi_settings_screen.dart @@ -7,6 +7,8 @@ import 'package:sf_localizations/sf_localizations.dart'; import 'package:utils/utils.dart'; import 'state/wifi_settings_view_model.dart'; +import 'state/wifi_settings_view_state.dart'; +import 'widgets/available_wifi_network_card.dart'; import 'widgets/add_wifi_network_sheet.dart'; import 'widgets/wifi_network_card.dart'; @@ -19,33 +21,41 @@ class WifiSettingsScreen extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final theme = ref.watch(themePortProvider); final state = ref.watch(wifiSettingsViewModelProvider); + final vm = ref.read(wifiSettingsViewModelProvider.notifier); final primaryColor = theme.getColorFor(ThemeCode.legacyPrimary); - ref.listen(wifiSettingsViewModelProvider.select((s) => s.errorMessage), ( + ref.listen(wifiSettingsViewModelProvider.select((s) => s.error), ( _, - errorMessage, + error, ) { - if (errorMessage.isNotEmpty) { - showTopSnackbar( - context, - message: errorMessage, - type: MessageType.error, - ); - } + if (error == null) return; + final message = switch (error) { + WifiSettingsError.loadFailed => context.translate(I18n.wifiLoadError), + WifiSettingsError.scanFailed => context.translate(I18n.wifiScanFailed), + WifiSettingsError.connectFailed => + context.translate(I18n.wifiConnectFailed), + WifiSettingsError.saveFailed => context.translate(I18n.wifiSaveFailed), + WifiSettingsError.deleteFailed => + context.translate(I18n.wifiDeleteFailed), + }; + showTopSnackbar(context, message: message, type: MessageType.error); + vm.clearError(); }); - ref.listen(wifiSettingsViewModelProvider.select((s) => s.successMessage), ( + ref.listen(wifiSettingsViewModelProvider.select((s) => s.success), ( _, - successMessage, + success, ) { - if (successMessage.isNotEmpty) { - showTopSnackbar( - context, - message: context.translate(successMessage), - type: MessageType.success, - ); - ref.read(wifiSettingsViewModelProvider.notifier).clearSuccess(); - } + if (success == null) return; + final message = switch (success) { + WifiSettingsSuccess.networkSaved => + context.translate(I18n.wifiNetworkSaved), + WifiSettingsSuccess.networkDeleted => + context.translate(I18n.wifiNetworkDeleted), + WifiSettingsSuccess.connected => context.translate(I18n.wifiConnected), + }; + showTopSnackbar(context, message: message, type: MessageType.success); + vm.clearSuccess(); }); return Scaffold( @@ -65,7 +75,7 @@ class WifiSettingsScreen extends ConsumerWidget { ), ), title: Text( - context.translate(I18n.wifiSettings).toUpperCase(), + 'WiFi', style: TextStyle( fontSize: SizeUtils.getByScreen(small: 20, big: 19), fontWeight: FontWeight.w500, @@ -86,10 +96,10 @@ class WifiSettingsScreen extends ConsumerWidget { child: IconButton( onPressed: () { if (!guardDeviceCommand(context, ref)) return; - showAddWifiNetworkSheet(context); + vm.scanNetworks(); }, icon: Icon( - Icons.add, + Icons.wifi_find, color: Colors.white, size: SizeUtils.getByScreen(small: 24, big: 22), ), @@ -102,68 +112,19 @@ class WifiSettingsScreen extends ConsumerWidget { top: false, child: state.isLoading ? const Center(child: CircularProgressIndicator()) - : state.networks.isEmpty - ? _EmptyState(primaryColor: primaryColor) - : _NetworkList(), + : _Body(), ), ); } } -class _EmptyState extends StatelessWidget { - final Color primaryColor; - - const _EmptyState({required this.primaryColor}); - - @override - Widget build(BuildContext context) { - return Center( - child: Padding( - padding: EdgeInsets.symmetric( - horizontal: SizeUtils.getByScreen(small: 32, big: 30), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Icons.wifi_off_outlined, - color: primaryColor, - size: SizeUtils.getByScreen(small: 120, big: 140), - ), - SizedBox(height: SizeUtils.getByScreen(small: 20, big: 24)), - Text( - context.translate(I18n.noWifiNetworks), - style: TextStyle( - fontSize: SizeUtils.getByScreen(small: 16, big: 17), - fontWeight: FontWeight.w500, - color: Colors.grey, - ), - ), - SizedBox(height: SizeUtils.getByScreen(small: 8, big: 10)), - Text( - context.translate(I18n.noWifiNetworksDescription), - textAlign: TextAlign.center, - style: TextStyle( - fontSize: SizeUtils.getByScreen(small: 14, big: 15), - color: Colors.grey, - ), - ), - ], - ), - ), - ); - } -} - -class _NetworkList extends ConsumerWidget { - const _NetworkList(); +class _Body extends ConsumerWidget { + const _Body(); @override Widget build(BuildContext context, WidgetRef ref) { final theme = ref.watch(themePortProvider); - final networks = ref.watch( - wifiSettingsViewModelProvider.select((s) => s.networks), - ); + final state = ref.watch(wifiSettingsViewModelProvider); final primaryColor = theme.getColorFor(ThemeCode.legacyPrimary); return SingleChildScrollView( @@ -175,46 +136,145 @@ class _NetworkList extends ConsumerWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Padding( - padding: EdgeInsets.only( - bottom: SizeUtils.getByScreen(small: 12, big: 10), - ), - child: Text( - context.translate(I18n.wifiDescription), - style: TextStyle( - fontSize: SizeUtils.getByScreen(small: 14, big: 15), - color: theme - .getColorFor(ThemeCode.textPrimary) - .withAlpha(178), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + _sectionTitle( + context, + context.translate(I18n.wifiCurrentNetwork), + primaryColor, + ), + if (state.isLoadingCurrentNetwork) + SizedBox( + width: SizeUtils.getByScreen(small: 16, big: 14), + height: SizeUtils.getByScreen(small: 16, big: 14), + child: CircularProgressIndicator( + strokeWidth: 2, + color: primaryColor, + ), + ), + ], + ), + SizedBox(height: SizeUtils.getByScreen(small: 8, big: 6)), + if (state.currentNetwork != null) + _CurrentNetworkCard( + ssid: state.currentNetwork!.ssid, + bssid: state.currentNetwork!.bssid, + theme: theme, + ) + else if (!state.isLoadingCurrentNetwork) + Padding( + padding: EdgeInsets.only( + bottom: SizeUtils.getByScreen(small: 12, big: 10), + ), + child: Text( + context.translate(I18n.wifiNoCurrentNetwork), + style: TextStyle( + fontSize: SizeUtils.getByScreen(small: 14, big: 15), + color: theme + .getColorFor(ThemeCode.textPrimary) + .withAlpha(178), + ), ), ), - ), - ...List.generate(networks.length, (index) { - final network = networks[index]; - return WifiNetworkCard( - network: network, - onDelete: () => _confirmDelete(context, ref, network), - theme: theme, - ); - }), - SizedBox(height: SizeUtils.getByScreen(small: 12, big: 10)), - Text( + if (state.availableNetworks.isNotEmpty || state.isScanning) ...[ + SizedBox(height: SizeUtils.getByScreen(small: 16, big: 14)), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + _sectionTitle( + context, + context.translate(I18n.wifiAvailableNetworks), + primaryColor, + ), + if (state.isScanning) + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + '${state.scanSecondsRemaining}s', + style: TextStyle( + fontSize: SizeUtils.getByScreen(small: 13, big: 12), + fontWeight: FontWeight.w600, + color: primaryColor, + ), + ), + SizedBox(width: SizeUtils.getByScreen(small: 6, big: 5)), + SizedBox( + width: SizeUtils.getByScreen(small: 16, big: 14), + height: SizeUtils.getByScreen(small: 16, big: 14), + child: CircularProgressIndicator( + strokeWidth: 2, + color: primaryColor, + ), + ), + ], + ), + ], + ), + SizedBox(height: SizeUtils.getByScreen(small: 8, big: 6)), + ...state.availableNetworks.map( + (network) => AvailableWifiNetworkCard( + network: network, + onTap: () => showConnectWifiSheet( + context, + ssid: network.ssid, + bssid: network.bssid, + ), + ), + ), + ], + SizedBox(height: SizeUtils.getByScreen(small: 16, big: 14)), + _sectionTitle( + context, context.translate( - I18n.wifiNetworksCount, - args: {'count': networks.length.toString()}, - ), - style: TextStyle( - fontSize: SizeUtils.getByScreen(small: 13, big: 14), - color: primaryColor, - fontWeight: FontWeight.w500, + I18n.wifiSavedNetworks, + args: {'count': state.savedNetworks.length.toString()}, ), + primaryColor, ), + SizedBox(height: SizeUtils.getByScreen(small: 8, big: 6)), + if (state.savedNetworks.isEmpty) + Padding( + padding: EdgeInsets.only( + bottom: SizeUtils.getByScreen(small: 12, big: 10), + ), + child: Text( + context.translate(I18n.noWifiNetworks), + style: TextStyle( + fontSize: SizeUtils.getByScreen(small: 14, big: 15), + color: theme + .getColorFor(ThemeCode.textPrimary) + .withAlpha(178), + ), + ), + ) + else + ...state.savedNetworks.map( + (network) => WifiNetworkCard( + network: network, + onDelete: () => _confirmDelete(context, ref, network), + theme: theme, + ), + ), ], ), ), ); } + Widget _sectionTitle(BuildContext context, String text, Color color) { + return Text( + text.toUpperCase(), + style: TextStyle( + fontSize: SizeUtils.getByScreen(small: 13, big: 14), + fontWeight: FontWeight.w600, + letterSpacing: 0.5, + color: color, + ), + ); + } + void _confirmDelete(BuildContext context, WidgetRef ref, dynamic network) { if (!guardDeviceCommand(context, ref)) return; final theme = ref.read(themePortProvider); @@ -255,3 +315,69 @@ class _NetworkList extends ConsumerWidget { ); } } + +class _CurrentNetworkCard extends StatelessWidget { + final String ssid; + final String bssid; + final ThemePort theme; + + const _CurrentNetworkCard({ + required this.ssid, + required this.bssid, + required this.theme, + }); + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.only( + bottom: SizeUtils.getByScreen(small: 10, big: 8), + ), + child: Container( + padding: EdgeInsets.symmetric( + horizontal: SizeUtils.getByScreen(small: 16, big: 14), + vertical: SizeUtils.getByScreen(small: 14, big: 12), + ), + decoration: BoxDecoration( + color: theme.getColorFor(ThemeCode.backgroundSecondary), + borderRadius: BorderRadius.all(Radius.circular(16)), + ), + child: Row( + children: [ + Icon( + Icons.wifi, + color: theme.getColorFor(ThemeCode.legacyPrimary), + size: SizeUtils.getByScreen(small: 28, big: 30), + ), + SizedBox(width: SizeUtils.getByScreen(small: 12, big: 14)), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + ssid, + style: TextStyle( + fontWeight: FontWeight.w600, + color: theme.getColorFor(ThemeCode.textPrimary), + fontSize: SizeUtils.getByScreen(small: 15, big: 16), + ), + ), + SizedBox(height: 2), + Text( + bssid, + style: TextStyle( + color: theme + .getColorFor(ThemeCode.textPrimary) + .withAlpha(178), + fontSize: SizeUtils.getByScreen(small: 13, big: 14), + ), + ), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/modules/legacy/packages/legacy_shared/lib/src/data/models/send_command_request_model.dart b/modules/legacy/packages/legacy_shared/lib/src/data/models/send_command_request_model.dart index 4b835ca6..9bb5302a 100644 --- a/modules/legacy/packages/legacy_shared/lib/src/data/models/send_command_request_model.dart +++ b/modules/legacy/packages/legacy_shared/lib/src/data/models/send_command_request_model.dart @@ -24,6 +24,14 @@ enum DeviceCommand { setBackgroundImage, @JsonValue('SET_SOUND_MODE') setSoundMode, + @JsonValue('WIFI_CURRENT') + wifiCurrent, + @JsonValue('WIFI_SEARCH') + wifiSearch, + @JsonValue('SET_WIFI') + setWifi, + @JsonValue('WIFI_DELETE') + wifiDelete, } @freezed diff --git a/modules/legacy/packages/legacy_shared/lib/src/data/models/send_command_request_model.g.dart b/modules/legacy/packages/legacy_shared/lib/src/data/models/send_command_request_model.g.dart index f81df431..ff690e76 100644 --- a/modules/legacy/packages/legacy_shared/lib/src/data/models/send_command_request_model.g.dart +++ b/modules/legacy/packages/legacy_shared/lib/src/data/models/send_command_request_model.g.dart @@ -33,4 +33,8 @@ const _$DeviceCommandEnumMap = { DeviceCommand.shutdown: 'SHUTDOWN', DeviceCommand.setBackgroundImage: 'SET_BACKGROUND_IMG', DeviceCommand.setSoundMode: 'SET_SOUND_MODE', + DeviceCommand.wifiCurrent: 'WIFI_CURRENT', + DeviceCommand.wifiSearch: 'WIFI_SEARCH', + DeviceCommand.setWifi: 'SET_WIFI', + DeviceCommand.wifiDelete: 'WIFI_DELETE', }; diff --git a/packages/sf_localizations/assets/l10n/de.json b/packages/sf_localizations/assets/l10n/de.json index 22c9e9c0..29cf4de6 100644 --- a/packages/sf_localizations/assets/l10n/de.json +++ b/packages/sf_localizations/assets/l10n/de.json @@ -576,6 +576,22 @@ "wifiBssid": "MAC-Adresse (BSSID)", "wifiSsidHint": "z.B. MeinHeimWLAN", "wifiBssidHint": "z.B. 0c:80:63:e4:cb:e1", + "wifiCurrentNetwork": "Aktuelles Netzwerk", + "wifiAvailableNetworks": "Verfügbare Netzwerke", + "wifiSavedNetworks": "{count} gespeicherte Netzwerke", + "wifiScan": "Scannen", + "wifiNoCurrentNetwork": "Kein Netzwerk verbunden", + "wifiLoadError": "Fehler beim Laden der WLAN-Netzwerke", + "wifiScanFailed": "Netzwerksuche fehlgeschlagen", + "wifiConnectFailed": "Verbindung fehlgeschlagen", + "wifiSaveFailed": "Netzwerk speichern fehlgeschlagen", + "wifiDeleteFailed": "Netzwerk löschen fehlgeschlagen", + "wifiNetworkSaved": "Netzwerk erfolgreich gespeichert", + "wifiNetworkDeleted": "Netzwerk erfolgreich gelöscht", + "wifiConnected": "Erfolgreich verbunden", + "wifiPassword": "Passwort", + "wifiPasswordHint": "Netzwerk-Passwort eingeben", + "wifiConnectToNetwork": "Mit Netzwerk verbinden", "editChildProfile": "Profil bearbeiten", "editChildProfileTitle": "Kinderprofil bearbeiten", "editChildProfileSaveSuccess": "Kinderprofil erfolgreich aktualisiert", diff --git a/packages/sf_localizations/assets/l10n/en.json b/packages/sf_localizations/assets/l10n/en.json index 8ae66092..896d29d4 100755 --- a/packages/sf_localizations/assets/l10n/en.json +++ b/packages/sf_localizations/assets/l10n/en.json @@ -733,6 +733,22 @@ "wifiBssid": "MAC address (BSSID)", "wifiSsidHint": "e.g. MyHomeWiFi", "wifiBssidHint": "e.g. 0c:80:63:e4:cb:e1", + "wifiCurrentNetwork": "Current network", + "wifiAvailableNetworks": "Available networks", + "wifiSavedNetworks": "{count} saved networks", + "wifiScan": "Scan", + "wifiNoCurrentNetwork": "No network connected", + "wifiLoadError": "Error loading WiFi networks", + "wifiScanFailed": "Failed to scan networks", + "wifiConnectFailed": "Failed to connect", + "wifiSaveFailed": "Failed to save network", + "wifiDeleteFailed": "Failed to delete network", + "wifiNetworkSaved": "Network saved successfully", + "wifiNetworkDeleted": "Network deleted successfully", + "wifiConnected": "Connected successfully", + "wifiPassword": "Password", + "wifiPasswordHint": "Enter the network password", + "wifiConnectToNetwork": "Connect to network", "editChildProfile": "Edit profile", "editChildProfileSaveSuccess": "Child profile updated successfully", "editChildProfileTitle": "Edit child profile", diff --git a/packages/sf_localizations/assets/l10n/es.json b/packages/sf_localizations/assets/l10n/es.json index 56939076..97c624ca 100644 --- a/packages/sf_localizations/assets/l10n/es.json +++ b/packages/sf_localizations/assets/l10n/es.json @@ -734,6 +734,22 @@ "wifiBssid": "Dirección MAC (BSSID)", "wifiSsidHint": "ej. MiWiFiCasa", "wifiBssidHint": "ej. 0c:80:63:e4:cb:e1", + "wifiCurrentNetwork": "Red actual", + "wifiAvailableNetworks": "Redes disponibles", + "wifiSavedNetworks": "{count} redes guardadas", + "wifiScan": "Escanear", + "wifiNoCurrentNetwork": "Sin red conectada", + "wifiLoadError": "Error al cargar redes WiFi", + "wifiScanFailed": "Error al escanear redes", + "wifiConnectFailed": "Error al conectar", + "wifiSaveFailed": "Error al guardar red", + "wifiDeleteFailed": "Error al eliminar red", + "wifiNetworkSaved": "Red guardada correctamente", + "wifiNetworkDeleted": "Red eliminada correctamente", + "wifiConnected": "Conectado correctamente", + "wifiPassword": "Contraseña", + "wifiPasswordHint": "Ingresa la contraseña de la red", + "wifiConnectToNetwork": "Conectar a red", "editChildProfile": "Editar perfil", "editChildProfileTitle": "Editar perfil del niño", "editChildProfileSaveSuccess": "Perfil del niño actualizado correctamente", diff --git a/packages/sf_localizations/assets/l10n/fr.json b/packages/sf_localizations/assets/l10n/fr.json index 86f4d02f..50f7b95f 100644 --- a/packages/sf_localizations/assets/l10n/fr.json +++ b/packages/sf_localizations/assets/l10n/fr.json @@ -576,6 +576,22 @@ "wifiBssid": "Adresse MAC (BSSID)", "wifiSsidHint": "ex. MonWiFiMaison", "wifiBssidHint": "ex. 0c:80:63:e4:cb:e1", + "wifiCurrentNetwork": "Réseau actuel", + "wifiAvailableNetworks": "Réseaux disponibles", + "wifiSavedNetworks": "{count} réseaux enregistrés", + "wifiScan": "Scanner", + "wifiNoCurrentNetwork": "Aucun réseau connecté", + "wifiLoadError": "Erreur lors du chargement des réseaux WiFi", + "wifiScanFailed": "Échec de la recherche de réseaux", + "wifiConnectFailed": "Échec de la connexion", + "wifiSaveFailed": "Échec de l'enregistrement du réseau", + "wifiDeleteFailed": "Échec de la suppression du réseau", + "wifiNetworkSaved": "Réseau enregistré avec succès", + "wifiNetworkDeleted": "Réseau supprimé avec succès", + "wifiConnected": "Connecté avec succès", + "wifiPassword": "Mot de passe", + "wifiPasswordHint": "Entrez le mot de passe du réseau", + "wifiConnectToNetwork": "Se connecter au réseau", "editChildProfile": "Modifier le profil", "editChildProfileTitle": "Modifier le profil de l'enfant", "editChildProfileSaveSuccess": "Profil de l'enfant mis à jour avec succès", diff --git a/packages/sf_localizations/assets/l10n/it.json b/packages/sf_localizations/assets/l10n/it.json index bf97c6cc..0909e1e5 100644 --- a/packages/sf_localizations/assets/l10n/it.json +++ b/packages/sf_localizations/assets/l10n/it.json @@ -576,6 +576,22 @@ "wifiBssid": "Indirizzo MAC (BSSID)", "wifiSsidHint": "es. MiaReteCasa", "wifiBssidHint": "es. 0c:80:63:e4:cb:e1", + "wifiCurrentNetwork": "Rete attuale", + "wifiAvailableNetworks": "Reti disponibili", + "wifiSavedNetworks": "{count} reti salvate", + "wifiScan": "Scansiona", + "wifiNoCurrentNetwork": "Nessuna rete connessa", + "wifiLoadError": "Errore nel caricamento delle reti WiFi", + "wifiScanFailed": "Scansione reti fallita", + "wifiConnectFailed": "Connessione fallita", + "wifiSaveFailed": "Salvataggio rete fallito", + "wifiDeleteFailed": "Eliminazione rete fallita", + "wifiNetworkSaved": "Rete salvata con successo", + "wifiNetworkDeleted": "Rete eliminata con successo", + "wifiConnected": "Connesso con successo", + "wifiPassword": "Password", + "wifiPasswordHint": "Inserisci la password della rete", + "wifiConnectToNetwork": "Connetti alla rete", "editChildProfile": "Modifica profilo", "editChildProfileTitle": "Modifica profilo del bambino", "editChildProfileSaveSuccess": "Profilo del bambino aggiornato con successo", diff --git a/packages/sf_localizations/assets/l10n/pt.json b/packages/sf_localizations/assets/l10n/pt.json index 3f6b7f97..a1b35dfd 100644 --- a/packages/sf_localizations/assets/l10n/pt.json +++ b/packages/sf_localizations/assets/l10n/pt.json @@ -576,6 +576,22 @@ "wifiBssid": "Endereço MAC (BSSID)", "wifiSsidHint": "ex. MinhaRedeWiFi", "wifiBssidHint": "ex. 0c:80:63:e4:cb:e1", + "wifiCurrentNetwork": "Rede atual", + "wifiAvailableNetworks": "Redes disponíveis", + "wifiSavedNetworks": "{count} redes guardadas", + "wifiScan": "Procurar", + "wifiNoCurrentNetwork": "Nenhuma rede conectada", + "wifiLoadError": "Erro ao carregar redes WiFi", + "wifiScanFailed": "Falha ao procurar redes", + "wifiConnectFailed": "Falha ao conectar", + "wifiSaveFailed": "Falha ao guardar rede", + "wifiDeleteFailed": "Falha ao eliminar rede", + "wifiNetworkSaved": "Rede guardada com sucesso", + "wifiNetworkDeleted": "Rede eliminada com sucesso", + "wifiConnected": "Conectado com sucesso", + "wifiPassword": "Palavra-passe", + "wifiPasswordHint": "Introduza a palavra-passe da rede", + "wifiConnectToNetwork": "Conectar à rede", "editChildProfile": "Editar perfil", "editChildProfileTitle": "Editar perfil da criança", "editChildProfileSaveSuccess": "Perfil da criança atualizado com sucesso", diff --git a/packages/sf_localizations/lib/src/generated/i18n.dart b/packages/sf_localizations/lib/src/generated/i18n.dart index 39b8aa54..4a3c36d4 100755 --- a/packages/sf_localizations/lib/src/generated/i18n.dart +++ b/packages/sf_localizations/lib/src/generated/i18n.dart @@ -986,12 +986,28 @@ class I18n { static const String wednesday = 'wednesday'; static const String welcome = 'welcome'; static const String whitelistDescription = 'whitelistDescription'; + static const String wifiAvailableNetworks = 'wifiAvailableNetworks'; static const String wifiBssid = 'wifiBssid'; static const String wifiBssidHint = 'wifiBssidHint'; + static const String wifiConnectFailed = 'wifiConnectFailed'; + static const String wifiConnectToNetwork = 'wifiConnectToNetwork'; + static const String wifiConnected = 'wifiConnected'; + static const String wifiCurrentNetwork = 'wifiCurrentNetwork'; + static const String wifiDeleteFailed = 'wifiDeleteFailed'; static const String wifiDescription = 'wifiDescription'; + static const String wifiLoadError = 'wifiLoadError'; static const String wifiNetworkAdded = 'wifiNetworkAdded'; + static const String wifiNetworkDeleted = 'wifiNetworkDeleted'; static const String wifiNetworkRemoved = 'wifiNetworkRemoved'; + static const String wifiNetworkSaved = 'wifiNetworkSaved'; static const String wifiNetworksCount = 'wifiNetworksCount'; + static const String wifiNoCurrentNetwork = 'wifiNoCurrentNetwork'; + static const String wifiPassword = 'wifiPassword'; + static const String wifiPasswordHint = 'wifiPasswordHint'; + static const String wifiSaveFailed = 'wifiSaveFailed'; + static const String wifiSavedNetworks = 'wifiSavedNetworks'; + static const String wifiScan = 'wifiScan'; + static const String wifiScanFailed = 'wifiScanFailed'; static const String wifiSettings = 'wifiSettings'; static const String wifiSsid = 'wifiSsid'; static const String wifiSsidHint = 'wifiSsidHint';