diff --git a/modules/legacy/modules/account/lib/src/core/data/datasource/devices_remote_datasource.dart b/modules/legacy/modules/account/lib/src/core/data/datasource/devices_remote_datasource.dart index a07a5282..07f0e917 100644 --- a/modules/legacy/modules/account/lib/src/core/data/datasource/devices_remote_datasource.dart +++ b/modules/legacy/modules/account/lib/src/core/data/datasource/devices_remote_datasource.dart @@ -1,7 +1,7 @@ -import 'package:account/src/features/linked_devices/domain/entities/update_device_request_entity.dart'; +import 'package:sf_shared/sf_shared.dart' show DeviceEntity; abstract class DevicesRemoteDatasource { Future deleteDevice({required String deviceId}); - Future updateDevice({required UpdateDeviceRequestEntity request}); + Future updateDevice({required DeviceEntity device}); } diff --git a/modules/legacy/modules/account/lib/src/core/data/datasource/devices_remote_datasource_impl.dart b/modules/legacy/modules/account/lib/src/core/data/datasource/devices_remote_datasource_impl.dart index 60f300f3..28c04308 100644 --- a/modules/legacy/modules/account/lib/src/core/data/datasource/devices_remote_datasource_impl.dart +++ b/modules/legacy/modules/account/lib/src/core/data/datasource/devices_remote_datasource_impl.dart @@ -1,6 +1,6 @@ -import 'package:account/src/core/data/models/update_device_request_dto.dart'; -import 'package:account/src/features/linked_devices/domain/entities/update_device_request_entity.dart'; +import 'package:legacy_device_state/legacy_device_state.dart'; import 'package:sf_infrastructure/sf_infrastructure.dart'; +import 'package:sf_shared/sf_shared.dart' show DeviceEntity; import 'devices_remote_datasource.dart'; @@ -15,10 +15,11 @@ class DevicesRemoteDatasourceImpl implements DevicesRemoteDatasource { } @override - Future updateDevice({ - required UpdateDeviceRequestEntity request, - }) async { - final body = request.toDto().toJson(); - await _repository.put('/devices', body: body); + Future updateDevice({required DeviceEntity device}) async { + final csvBase64 = DeviceCsvBuilder.buildBase64Csv( + device: device, + settings: device.settings, + ); + await _repository.put('/devices', body: {'csv': csvBase64}); } } diff --git a/modules/legacy/modules/account/lib/src/core/data/models/update_device_request_dto.dart b/modules/legacy/modules/account/lib/src/core/data/models/update_device_request_dto.dart deleted file mode 100644 index 7213253e..00000000 --- a/modules/legacy/modules/account/lib/src/core/data/models/update_device_request_dto.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:account/src/features/linked_devices/domain/entities/update_device_request_entity.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'update_device_request_dto.freezed.dart'; -part 'update_device_request_dto.g.dart'; - -@freezed -abstract class UpdateDeviceRequestDto with _$UpdateDeviceRequestDto { - const factory UpdateDeviceRequestDto({ - required String identificator, - required String carrierName, - }) = _UpdateDeviceRequestDto; - - factory UpdateDeviceRequestDto.fromJson(Map json) => - _$UpdateDeviceRequestDtoFromJson(json); -} - -extension UpdateDeviceRequestDtoMapper on UpdateDeviceRequestEntity { - UpdateDeviceRequestDto toDto() => UpdateDeviceRequestDto( - identificator: identificator, - carrierName: carrierName, - ); -} diff --git a/modules/legacy/modules/account/lib/src/core/data/models/update_device_request_dto.freezed.dart b/modules/legacy/modules/account/lib/src/core/data/models/update_device_request_dto.freezed.dart deleted file mode 100644 index 4fbf4b09..00000000 --- a/modules/legacy/modules/account/lib/src/core/data/models/update_device_request_dto.freezed.dart +++ /dev/null @@ -1,280 +0,0 @@ -// 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 'update_device_request_dto.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -// dart format off -T _$identity(T value) => value; - -/// @nodoc -mixin _$UpdateDeviceRequestDto { - - String get identificator; String get carrierName; -/// Create a copy of UpdateDeviceRequestDto -/// with the given fields replaced by the non-null parameter values. -@JsonKey(includeFromJson: false, includeToJson: false) -@pragma('vm:prefer-inline') -$UpdateDeviceRequestDtoCopyWith get copyWith => _$UpdateDeviceRequestDtoCopyWithImpl(this as UpdateDeviceRequestDto, _$identity); - - /// Serializes this UpdateDeviceRequestDto to a JSON map. - Map toJson(); - - -@override -bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is UpdateDeviceRequestDto&&(identical(other.identificator, identificator) || other.identificator == identificator)&&(identical(other.carrierName, carrierName) || other.carrierName == carrierName)); -} - -@JsonKey(includeFromJson: false, includeToJson: false) -@override -int get hashCode => Object.hash(runtimeType,identificator,carrierName); - -@override -String toString() { - return 'UpdateDeviceRequestDto(identificator: $identificator, carrierName: $carrierName)'; -} - - -} - -/// @nodoc -abstract mixin class $UpdateDeviceRequestDtoCopyWith<$Res> { - factory $UpdateDeviceRequestDtoCopyWith(UpdateDeviceRequestDto value, $Res Function(UpdateDeviceRequestDto) _then) = _$UpdateDeviceRequestDtoCopyWithImpl; -@useResult -$Res call({ - String identificator, String carrierName -}); - - - - -} -/// @nodoc -class _$UpdateDeviceRequestDtoCopyWithImpl<$Res> - implements $UpdateDeviceRequestDtoCopyWith<$Res> { - _$UpdateDeviceRequestDtoCopyWithImpl(this._self, this._then); - - final UpdateDeviceRequestDto _self; - final $Res Function(UpdateDeviceRequestDto) _then; - -/// Create a copy of UpdateDeviceRequestDto -/// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? identificator = null,Object? carrierName = null,}) { - return _then(_self.copyWith( -identificator: null == identificator ? _self.identificator : identificator // ignore: cast_nullable_to_non_nullable -as String,carrierName: null == carrierName ? _self.carrierName : carrierName // ignore: cast_nullable_to_non_nullable -as String, - )); -} - -} - - -/// Adds pattern-matching-related methods to [UpdateDeviceRequestDto]. -extension UpdateDeviceRequestDtoPatterns on UpdateDeviceRequestDto { -/// 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( _UpdateDeviceRequestDto value)? $default,{required TResult orElse(),}){ -final _that = this; -switch (_that) { -case _UpdateDeviceRequestDto() 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( _UpdateDeviceRequestDto value) $default,){ -final _that = this; -switch (_that) { -case _UpdateDeviceRequestDto(): -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( _UpdateDeviceRequestDto value)? $default,){ -final _that = this; -switch (_that) { -case _UpdateDeviceRequestDto() 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 identificator, String carrierName)? $default,{required TResult orElse(),}) {final _that = this; -switch (_that) { -case _UpdateDeviceRequestDto() when $default != null: -return $default(_that.identificator,_that.carrierName);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 identificator, String carrierName) $default,) {final _that = this; -switch (_that) { -case _UpdateDeviceRequestDto(): -return $default(_that.identificator,_that.carrierName);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 identificator, String carrierName)? $default,) {final _that = this; -switch (_that) { -case _UpdateDeviceRequestDto() when $default != null: -return $default(_that.identificator,_that.carrierName);case _: - return null; - -} -} - -} - -/// @nodoc -@JsonSerializable() - -class _UpdateDeviceRequestDto implements UpdateDeviceRequestDto { - const _UpdateDeviceRequestDto({required this.identificator, required this.carrierName}); - factory _UpdateDeviceRequestDto.fromJson(Map json) => _$UpdateDeviceRequestDtoFromJson(json); - -@override final String identificator; -@override final String carrierName; - -/// Create a copy of UpdateDeviceRequestDto -/// with the given fields replaced by the non-null parameter values. -@override @JsonKey(includeFromJson: false, includeToJson: false) -@pragma('vm:prefer-inline') -_$UpdateDeviceRequestDtoCopyWith<_UpdateDeviceRequestDto> get copyWith => __$UpdateDeviceRequestDtoCopyWithImpl<_UpdateDeviceRequestDto>(this, _$identity); - -@override -Map toJson() { - return _$UpdateDeviceRequestDtoToJson(this, ); -} - -@override -bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _UpdateDeviceRequestDto&&(identical(other.identificator, identificator) || other.identificator == identificator)&&(identical(other.carrierName, carrierName) || other.carrierName == carrierName)); -} - -@JsonKey(includeFromJson: false, includeToJson: false) -@override -int get hashCode => Object.hash(runtimeType,identificator,carrierName); - -@override -String toString() { - return 'UpdateDeviceRequestDto(identificator: $identificator, carrierName: $carrierName)'; -} - - -} - -/// @nodoc -abstract mixin class _$UpdateDeviceRequestDtoCopyWith<$Res> implements $UpdateDeviceRequestDtoCopyWith<$Res> { - factory _$UpdateDeviceRequestDtoCopyWith(_UpdateDeviceRequestDto value, $Res Function(_UpdateDeviceRequestDto) _then) = __$UpdateDeviceRequestDtoCopyWithImpl; -@override @useResult -$Res call({ - String identificator, String carrierName -}); - - - - -} -/// @nodoc -class __$UpdateDeviceRequestDtoCopyWithImpl<$Res> - implements _$UpdateDeviceRequestDtoCopyWith<$Res> { - __$UpdateDeviceRequestDtoCopyWithImpl(this._self, this._then); - - final _UpdateDeviceRequestDto _self; - final $Res Function(_UpdateDeviceRequestDto) _then; - -/// Create a copy of UpdateDeviceRequestDto -/// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? identificator = null,Object? carrierName = null,}) { - return _then(_UpdateDeviceRequestDto( -identificator: null == identificator ? _self.identificator : identificator // ignore: cast_nullable_to_non_nullable -as String,carrierName: null == carrierName ? _self.carrierName : carrierName // ignore: cast_nullable_to_non_nullable -as String, - )); -} - - -} - -// dart format on diff --git a/modules/legacy/modules/account/lib/src/core/data/models/update_device_request_dto.g.dart b/modules/legacy/modules/account/lib/src/core/data/models/update_device_request_dto.g.dart deleted file mode 100644 index 1445b748..00000000 --- a/modules/legacy/modules/account/lib/src/core/data/models/update_device_request_dto.g.dart +++ /dev/null @@ -1,21 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'update_device_request_dto.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -_UpdateDeviceRequestDto _$UpdateDeviceRequestDtoFromJson( - Map json, -) => _UpdateDeviceRequestDto( - identificator: json['identificator'] as String, - carrierName: json['carrierName'] as String, -); - -Map _$UpdateDeviceRequestDtoToJson( - _UpdateDeviceRequestDto instance, -) => { - 'identificator': instance.identificator, - 'carrierName': instance.carrierName, -}; diff --git a/modules/legacy/modules/account/lib/src/core/data/repositories/devices_repository_impl.dart b/modules/legacy/modules/account/lib/src/core/data/repositories/devices_repository_impl.dart index e1a6eed3..0a12f5b7 100644 --- a/modules/legacy/modules/account/lib/src/core/data/repositories/devices_repository_impl.dart +++ b/modules/legacy/modules/account/lib/src/core/data/repositories/devices_repository_impl.dart @@ -1,7 +1,7 @@ import 'package:account/src/core/data/datasource/devices_remote_datasource.dart'; -import 'package:account/src/features/linked_devices/domain/entities/update_device_request_entity.dart'; import 'package:dio/dio.dart'; import 'package:sf_infrastructure/sf_infrastructure.dart'; +import 'package:sf_shared/sf_shared.dart' show DeviceEntity; import '../../domain/repositories/devices_repository.dart'; @@ -20,9 +20,9 @@ class DevicesRepositoryImpl implements DevicesRepository { } @override - Future updateDevice({required UpdateDeviceRequestEntity request}) async { + Future updateDevice({required DeviceEntity device}) async { try { - await _remote.updateDevice(request: request); + await _remote.updateDevice(device: device); } on DioException catch (error) { throw mapDioError(error, defaultMessage: 'Error to update device'); } diff --git a/modules/legacy/modules/account/lib/src/core/domain/repositories/devices_repository.dart b/modules/legacy/modules/account/lib/src/core/domain/repositories/devices_repository.dart index 2488a007..67a702a9 100644 --- a/modules/legacy/modules/account/lib/src/core/domain/repositories/devices_repository.dart +++ b/modules/legacy/modules/account/lib/src/core/domain/repositories/devices_repository.dart @@ -1,7 +1,7 @@ -import 'package:account/src/features/linked_devices/domain/entities/update_device_request_entity.dart'; +import 'package:sf_shared/sf_shared.dart' show DeviceEntity; abstract class DevicesRepository { Future deleteDevice({required String deviceId}); - Future updateDevice({required UpdateDeviceRequestEntity request}); + Future updateDevice({required DeviceEntity device}); } diff --git a/modules/legacy/modules/account/lib/src/features/linked_devices/domain/entities/update_device_request_entity.dart b/modules/legacy/modules/account/lib/src/features/linked_devices/domain/entities/update_device_request_entity.dart deleted file mode 100644 index eb2ac9cb..00000000 --- a/modules/legacy/modules/account/lib/src/features/linked_devices/domain/entities/update_device_request_entity.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; - -part 'update_device_request_entity.freezed.dart'; - -@freezed -abstract class UpdateDeviceRequestEntity with _$UpdateDeviceRequestEntity { - const factory UpdateDeviceRequestEntity({ - required String identificator, - required String carrierName, - }) = _UpdateDeviceRequestEntity; -} diff --git a/modules/legacy/modules/account/lib/src/features/linked_devices/domain/entities/update_device_request_entity.freezed.dart b/modules/legacy/modules/account/lib/src/features/linked_devices/domain/entities/update_device_request_entity.freezed.dart deleted file mode 100644 index edce7734..00000000 --- a/modules/legacy/modules/account/lib/src/features/linked_devices/domain/entities/update_device_request_entity.freezed.dart +++ /dev/null @@ -1,274 +0,0 @@ -// 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 'update_device_request_entity.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -// dart format off -T _$identity(T value) => value; -/// @nodoc -mixin _$UpdateDeviceRequestEntity { - - String get identificator; String get carrierName; -/// Create a copy of UpdateDeviceRequestEntity -/// with the given fields replaced by the non-null parameter values. -@JsonKey(includeFromJson: false, includeToJson: false) -@pragma('vm:prefer-inline') -$UpdateDeviceRequestEntityCopyWith get copyWith => _$UpdateDeviceRequestEntityCopyWithImpl(this as UpdateDeviceRequestEntity, _$identity); - - - -@override -bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is UpdateDeviceRequestEntity&&(identical(other.identificator, identificator) || other.identificator == identificator)&&(identical(other.carrierName, carrierName) || other.carrierName == carrierName)); -} - - -@override -int get hashCode => Object.hash(runtimeType,identificator,carrierName); - -@override -String toString() { - return 'UpdateDeviceRequestEntity(identificator: $identificator, carrierName: $carrierName)'; -} - - -} - -/// @nodoc -abstract mixin class $UpdateDeviceRequestEntityCopyWith<$Res> { - factory $UpdateDeviceRequestEntityCopyWith(UpdateDeviceRequestEntity value, $Res Function(UpdateDeviceRequestEntity) _then) = _$UpdateDeviceRequestEntityCopyWithImpl; -@useResult -$Res call({ - String identificator, String carrierName -}); - - - - -} -/// @nodoc -class _$UpdateDeviceRequestEntityCopyWithImpl<$Res> - implements $UpdateDeviceRequestEntityCopyWith<$Res> { - _$UpdateDeviceRequestEntityCopyWithImpl(this._self, this._then); - - final UpdateDeviceRequestEntity _self; - final $Res Function(UpdateDeviceRequestEntity) _then; - -/// Create a copy of UpdateDeviceRequestEntity -/// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? identificator = null,Object? carrierName = null,}) { - return _then(_self.copyWith( -identificator: null == identificator ? _self.identificator : identificator // ignore: cast_nullable_to_non_nullable -as String,carrierName: null == carrierName ? _self.carrierName : carrierName // ignore: cast_nullable_to_non_nullable -as String, - )); -} - -} - - -/// Adds pattern-matching-related methods to [UpdateDeviceRequestEntity]. -extension UpdateDeviceRequestEntityPatterns on UpdateDeviceRequestEntity { -/// 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( _UpdateDeviceRequestEntity value)? $default,{required TResult orElse(),}){ -final _that = this; -switch (_that) { -case _UpdateDeviceRequestEntity() 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( _UpdateDeviceRequestEntity value) $default,){ -final _that = this; -switch (_that) { -case _UpdateDeviceRequestEntity(): -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( _UpdateDeviceRequestEntity value)? $default,){ -final _that = this; -switch (_that) { -case _UpdateDeviceRequestEntity() 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 identificator, String carrierName)? $default,{required TResult orElse(),}) {final _that = this; -switch (_that) { -case _UpdateDeviceRequestEntity() when $default != null: -return $default(_that.identificator,_that.carrierName);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 identificator, String carrierName) $default,) {final _that = this; -switch (_that) { -case _UpdateDeviceRequestEntity(): -return $default(_that.identificator,_that.carrierName);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 identificator, String carrierName)? $default,) {final _that = this; -switch (_that) { -case _UpdateDeviceRequestEntity() when $default != null: -return $default(_that.identificator,_that.carrierName);case _: - return null; - -} -} - -} - -/// @nodoc - - -class _UpdateDeviceRequestEntity implements UpdateDeviceRequestEntity { - const _UpdateDeviceRequestEntity({required this.identificator, required this.carrierName}); - - -@override final String identificator; -@override final String carrierName; - -/// Create a copy of UpdateDeviceRequestEntity -/// with the given fields replaced by the non-null parameter values. -@override @JsonKey(includeFromJson: false, includeToJson: false) -@pragma('vm:prefer-inline') -_$UpdateDeviceRequestEntityCopyWith<_UpdateDeviceRequestEntity> get copyWith => __$UpdateDeviceRequestEntityCopyWithImpl<_UpdateDeviceRequestEntity>(this, _$identity); - - - -@override -bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _UpdateDeviceRequestEntity&&(identical(other.identificator, identificator) || other.identificator == identificator)&&(identical(other.carrierName, carrierName) || other.carrierName == carrierName)); -} - - -@override -int get hashCode => Object.hash(runtimeType,identificator,carrierName); - -@override -String toString() { - return 'UpdateDeviceRequestEntity(identificator: $identificator, carrierName: $carrierName)'; -} - - -} - -/// @nodoc -abstract mixin class _$UpdateDeviceRequestEntityCopyWith<$Res> implements $UpdateDeviceRequestEntityCopyWith<$Res> { - factory _$UpdateDeviceRequestEntityCopyWith(_UpdateDeviceRequestEntity value, $Res Function(_UpdateDeviceRequestEntity) _then) = __$UpdateDeviceRequestEntityCopyWithImpl; -@override @useResult -$Res call({ - String identificator, String carrierName -}); - - - - -} -/// @nodoc -class __$UpdateDeviceRequestEntityCopyWithImpl<$Res> - implements _$UpdateDeviceRequestEntityCopyWith<$Res> { - __$UpdateDeviceRequestEntityCopyWithImpl(this._self, this._then); - - final _UpdateDeviceRequestEntity _self; - final $Res Function(_UpdateDeviceRequestEntity) _then; - -/// Create a copy of UpdateDeviceRequestEntity -/// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? identificator = null,Object? carrierName = null,}) { - return _then(_UpdateDeviceRequestEntity( -identificator: null == identificator ? _self.identificator : identificator // ignore: cast_nullable_to_non_nullable -as String,carrierName: null == carrierName ? _self.carrierName : carrierName // ignore: cast_nullable_to_non_nullable -as String, - )); -} - - -} - -// dart format on diff --git a/modules/legacy/modules/account/lib/src/features/linked_devices/domain/entities/update_devices_request_entity.freezed.dart b/modules/legacy/modules/account/lib/src/features/linked_devices/domain/entities/update_devices_request_entity.freezed.dart deleted file mode 100644 index 6460aeb5..00000000 --- a/modules/legacy/modules/account/lib/src/features/linked_devices/domain/entities/update_devices_request_entity.freezed.dart +++ /dev/null @@ -1 +0,0 @@ -part of 'update_device_request_entity.dart'; diff --git a/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/edit_linked_device_screen.dart b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/edit_linked_device_screen.dart index b7d5d11a..565d19d2 100644 --- a/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/edit_linked_device_screen.dart +++ b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/edit_linked_device_screen.dart @@ -1,28 +1,71 @@ -import 'package:account/src/features/linked_devices/presentation/state/linked_devices_view_model.dart'; -import 'package:legacy_theme/legacy_theme.dart'; +import 'package:account/src/features/linked_devices/presentation/providers/linked_devices_controller.dart'; +import 'package:account/src/features/linked_devices/presentation/providers/linked_devices_edit_mode_provider.dart'; import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:legacy_theme/legacy_theme.dart'; import 'package:legacy_ui/legacy_ui.dart'; import 'package:sf_localizations/sf_localizations.dart'; +import 'package:sf_shared/sf_shared.dart'; import 'package:utils/utils.dart'; -class EditLinkedDeviceScreen extends ConsumerWidget { - const EditLinkedDeviceScreen({super.key}); +class EditLinkedDeviceScreen extends ConsumerStatefulWidget { + final DeviceEntity device; + + const EditLinkedDeviceScreen({super.key, required this.device}); @override - Widget build(BuildContext context, WidgetRef ref) { + ConsumerState createState() => + _EditLinkedDeviceScreenState(); +} - final vm = ref.read(linkedDevicesViewModelProvider.notifier); - final device = ref.watch( - linkedDevicesViewModelProvider.select((s) => s.selectedDevice), +class _EditLinkedDeviceScreenState + extends ConsumerState { + late final TextEditingController _nameController; + + @override + void initState() { + super.initState(); + _nameController = TextEditingController( + text: widget.device.carrierName ?? '', ); + } + + @override + void dispose() { + _nameController.dispose(); + super.dispose(); + } + + void _onSubmit() { + if (_nameController.text.trim().isEmpty) return; + ref.read(linkedDevicesControllerProvider.notifier).updateDevice( + device: widget.device, + newName: _nameController.text, + ); + } + + @override + Widget build(BuildContext context) { + ref.listen(linkedDevicesControllerProvider, (prev, next) async { + next.showErrorOn(context); + if (prev != null && + prev.isLoading && + !next.isLoading && + !next.hasError) { + await showSuccessDialog(context, I18n.deviceUpdatedSuccess); + if (context.mounted) { + ref.read(linkedDevicesEditModeProvider.notifier).disable(); + Navigator.of(context).pop(); + } + } + }); + + final submitState = ref.watch(linkedDevicesControllerProvider); return LegacyPageLayout( title: context.translate(I18n.editDeviceTitle), - showEdit: true, - onEditChange: vm.toggleIsEditing, body: Column( children: [ SizedBox(height: SizeUtils.getByScreen(small: 20, big: 18)), @@ -33,100 +76,65 @@ class EditLinkedDeviceScreen extends ConsumerWidget { big: EdgeInsets.symmetric(horizontal: 47, vertical: 8), ), child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.center, + Stack( children: [ - Stack( - children: [ - DecoratedBox( - decoration: BoxDecoration(color: Colors.blueAccent), - ), - Center( - child: SvgPicture.asset( - 'assets/shared/images/profile.svg', - ), - ), - Center( - child: SizedBox( - width: 160, - height: 160, - child: Align( - alignment: Alignment.bottomRight, - child: IconButton( - onPressed: () {}, - icon: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Color(0xFFCAC9C9), - ), - padding: EdgeInsets.all(8), - child: Icon( - Icons.edit_outlined, - color: Colors.white, - size: SizeUtils.getByScreen( - small: 32, - big: 30, - ), - ), + const DecoratedBox( + decoration: BoxDecoration(color: Colors.blueAccent), + ), + Center( + child: SvgPicture.asset( + 'assets/shared/images/profile.svg', + ), + ), + Center( + child: SizedBox( + width: 160, + height: 160, + child: Align( + alignment: Alignment.bottomRight, + child: IconButton( + onPressed: () {}, + icon: Container( + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: Color(0xFFCAC9C9), + ), + padding: const EdgeInsets.all(8), + child: Icon( + Icons.edit_outlined, + color: Colors.white, + size: SizeUtils.getByScreen( + small: 32, + big: 30, ), ), ), ), ), - ], - ), - SizedBox( - height: SizeUtils.getByScreen(small: 24, big: 22), - ), - CustomTextField( - controller: vm.deviceNameController, - hint: device!.carrierName!, - label: context.translate(I18n.name), + ), ), ], ), + SizedBox(height: SizeUtils.getByScreen(small: 24, big: 22)), + CustomTextField( + controller: _nameController, + hint: widget.device.carrierName ?? '', + label: context.translate(I18n.name), + ), ], ), ), ), ], ), - footer: _SaveSection(), - ); - } -} - -class _SaveSection extends ConsumerWidget { - const _SaveSection(); - - @override - Widget build(BuildContext context, WidgetRef ref) { - - final vm = ref.read(linkedDevicesViewModelProvider.notifier); - - return Padding( - padding: EdgeInsets.symmetric(horizontal: 24, vertical: 10), - child: PrimaryButton( - onPressed: () async { - await vm.updateDevice(); - if (!context.mounted) return; - - final errorMessage = ref.read( - linkedDevicesViewModelProvider.select((s) => s.errorMessage), - ); - - if (errorMessage.isNotEmpty) { - showTopSnackbar( - context, - message: errorMessage, - type: MessageType.error, - ); - } - }, - text: context.translate(I18n.save), - color: context.sfColors.legacyPrimary, + footer: Padding( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 10), + child: PrimaryButton( + onPressed: submitState.isLoading ? null : _onSubmit, + text: context.translate(I18n.save), + color: context.sfColors.legacyPrimary, + ), ), ); } diff --git a/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/linked_devices_screen.dart b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/linked_devices_screen.dart index edfd6f7b..22358959 100644 --- a/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/linked_devices_screen.dart +++ b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/linked_devices_screen.dart @@ -1,10 +1,11 @@ import 'package:account/src/features/linked_devices/presentation/edit_linked_device_screen.dart'; -import 'package:legacy_theme/legacy_theme.dart'; -import 'package:account/src/features/linked_devices/presentation/state/linked_devices_view_model.dart'; +import 'package:account/src/features/linked_devices/presentation/providers/linked_devices_controller.dart'; +import 'package:account/src/features/linked_devices/presentation/providers/linked_devices_edit_mode_provider.dart'; import 'package:account/src/features/linked_devices/presentation/widgets/delete_device_dialog.dart'; import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:legacy_theme/legacy_theme.dart'; import 'package:legacy_ui/legacy_ui.dart'; import 'package:navigation/navigation.dart'; import 'package:sf_localizations/sf_localizations.dart'; @@ -18,60 +19,66 @@ class LinkedDevicesScreen extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final vm = ref.read(linkedDevicesViewModelProvider.notifier); - final state = ref.watch(linkedDevicesViewModelProvider); + final devicesAsync = ref.watch(legacyDevicesProvider); + final isEditing = ref.watch(linkedDevicesEditModeProvider); + final toggleEditing = ref + .read(linkedDevicesEditModeProvider.notifier) + .toggle; + ref.listen(linkedDevicesControllerProvider, (prev, next) async { + next.showErrorOn(context); + if (prev != null && + prev.isLoading && + !next.isLoading && + !next.hasError) { + await showSuccessDialog(context, I18n.deviceDeletedSuccess); + if (!context.mounted) return; + ref.read(linkedDevicesEditModeProvider.notifier).disable(); + final remaining = ref.read(legacyDevicesProvider).value ?? const []; + if (remaining.isEmpty) { + navigationContract.goTo(AppRoutes.legacyDeviceSetup); + } + } + }); return LegacyPageLayout( title: context.translate(I18n.linkedDevices), showEdit: true, - onEditChange: vm.toggleIsEditing, - body: state.isLoading - ? const Center(child: CircularProgressIndicator()) - : Padding( - padding: EdgeInsets.symmetric( - horizontal: SizeUtils.getByScreen(small: 10, big: 12), - ), - child: ListView.separated( - itemBuilder: (BuildContext context, int index) => - _LinkedDeviceCard( - navigationContract: navigationContract, - device: state.linkedDevices[index], - isEditing: state.isEditing, - onDelete: () => - vm.deleteDevice(state.linkedDevices[index]), - ), - separatorBuilder: (BuildContext context, int index) => - SizedBox(height: SizeUtils.getByScreen(small: 18, big: 17)), - itemCount: state.linkedDevices.length, - ), + onEditChange: toggleEditing, + body: devicesAsync.when( + data: (devices) => Padding( + padding: EdgeInsets.symmetric( + horizontal: SizeUtils.getByScreen(small: 10, big: 12), + ), + child: ListView.separated( + itemBuilder: (_, index) => _LinkedDeviceCard( + device: devices[index], + isEditing: isEditing, ), + separatorBuilder: (_, __) => + SizedBox(height: SizeUtils.getByScreen(small: 18, big: 17)), + itemCount: devices.length, + ), + ), + loading: () => const Center(child: CircularProgressIndicator()), + error: (_, __) => const SizedBox.shrink(), + ), ); } } -class _LinkedDeviceCard extends ConsumerWidget { - final NavigationContract navigationContract; +class _LinkedDeviceCard extends StatelessWidget { final DeviceEntity device; final bool isEditing; - final Function onDelete; - const _LinkedDeviceCard({ - required this.navigationContract, - required this.device, - required this.isEditing, - required this.onDelete, - }); + const _LinkedDeviceCard({required this.device, required this.isEditing}); @override - Widget build(BuildContext context, WidgetRef ref) { - - final vm = ref.read(linkedDevicesViewModelProvider.notifier); - + Widget build(BuildContext context) { return Container( padding: SizeUtils.getByScreen( - small: EdgeInsets.symmetric(horizontal: 22, vertical: 10), - big: EdgeInsets.symmetric(horizontal: 21, vertical: 8), + small: const EdgeInsets.symmetric(horizontal: 22, vertical: 10), + big: const EdgeInsets.symmetric(horizontal: 21, vertical: 8), ), decoration: BoxDecoration( borderRadius: BorderRadius.all( @@ -100,7 +107,7 @@ class _LinkedDeviceCard extends ConsumerWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - device.carrierName!, + device.carrierName ?? '', style: TextStyle( fontSize: SizeUtils.getByScreen(small: 18, big: 19), fontWeight: FontWeight.w500, @@ -119,38 +126,30 @@ class _LinkedDeviceCard extends ConsumerWidget { DecoratedBox( decoration: BoxDecoration( color: Theme.of(context).colorScheme.error, - borderRadius: BorderRadius.all(Radius.circular(12)), + borderRadius: const BorderRadius.all(Radius.circular(12)), ), child: IconButton( - onPressed: () { - showDialog( - context: context, - builder: (context) => Dialog( - child: DeleteDeviceDialog( - navigationContract: navigationContract, - device: device, - ), - ), - ); - }, - icon: Icon(Icons.close, color: Colors.white), + onPressed: () => showDialog( + context: context, + builder: (_) => Dialog(child: DeleteDeviceDialog(device: device)), + ), + icon: const Icon(Icons.close, color: Colors.white), ), ), SizedBox(width: SizeUtils.getByScreen(small: 16, big: 14)), DecoratedBox( decoration: BoxDecoration( color: context.sfColors.legacyPrimary, - borderRadius: BorderRadius.all(Radius.circular(12)), + borderRadius: const BorderRadius.all(Radius.circular(12)), ), child: IconButton( - onPressed: () { - vm.setSelectedDevice(device); - Navigator.push( - context, - MaterialPageRoute(builder: (_) => EditLinkedDeviceScreen()), - ); - }, - icon: Icon(Icons.edit_outlined, color: Colors.white), + onPressed: () => Navigator.push( + context, + MaterialPageRoute( + builder: (_) => EditLinkedDeviceScreen(device: device), + ), + ), + icon: const Icon(Icons.edit_outlined, color: Colors.white), ), ), ], diff --git a/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/providers/linked_devices_controller.dart b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/providers/linked_devices_controller.dart new file mode 100644 index 00000000..e6e417b6 --- /dev/null +++ b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/providers/linked_devices_controller.dart @@ -0,0 +1,51 @@ +import 'dart:async'; + +import 'package:account/src/core/providers/devices_repository_provider.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:sf_shared/sf_shared.dart'; +import 'package:sf_tracking/sf_tracking.dart'; + +part 'linked_devices_controller.g.dart'; + +@riverpod +class LinkedDevicesController extends _$LinkedDevicesController { + @override + FutureOr build() {} + + Future deleteDevice(DeviceEntity device) async { + state = const AsyncLoading(); + state = await AsyncValue.guard(() async { + await ref + .read(devicesRepositoryProvider) + .deleteDevice(deviceId: device.id); + ref.read(legacyDevicesProvider.notifier).removeDevice(device.id); + + final currentSelected = ref.read(selectedDeviceProvider).value; + if (currentSelected?.id == device.id) { + ref.invalidate(selectedDeviceProvider); + } + + unawaited( + ref.read(sfTrackingProvider).legacyAccountLinkedDeviceUnlinked(), + ); + }); + } + + Future updateDevice({ + required DeviceEntity device, + required String newName, + }) async { + state = const AsyncLoading(); + state = await AsyncValue.guard(() async { + final trimmed = newName.trim(); + final updated = device.copyWith(carrierName: trimmed); + await ref.read(devicesRepositoryProvider).updateDevice(device: updated); + ref + .read(legacyDevicesProvider.notifier) + .renameDevice(deviceId: device.id, newCarrierName: trimmed); + unawaited( + ref.read(sfTrackingProvider).legacyAccountLinkedDeviceRenamed(), + ); + }); + } +} diff --git a/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/providers/linked_devices_controller.g.dart b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/providers/linked_devices_controller.g.dart new file mode 100644 index 00000000..0997c113 --- /dev/null +++ b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/providers/linked_devices_controller.g.dart @@ -0,0 +1,56 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'linked_devices_controller.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint, type=warning + +@ProviderFor(LinkedDevicesController) +const linkedDevicesControllerProvider = LinkedDevicesControllerProvider._(); + +final class LinkedDevicesControllerProvider + extends $AsyncNotifierProvider { + const LinkedDevicesControllerProvider._() + : super( + from: null, + argument: null, + retry: null, + name: r'linkedDevicesControllerProvider', + isAutoDispose: true, + dependencies: null, + $allTransitiveDependencies: null, + ); + + @override + String debugGetCreateSourceHash() => _$linkedDevicesControllerHash(); + + @$internal + @override + LinkedDevicesController create() => LinkedDevicesController(); +} + +String _$linkedDevicesControllerHash() => + r'5840696cb5ad0e8dd1b8f671180af74eeb42ba9d'; + +abstract class _$LinkedDevicesController extends $AsyncNotifier { + FutureOr build(); + @$mustCallSuper + @override + void runBuild() { + build(); + final ref = this.ref as $Ref, void>; + final element = + ref.element + as $ClassProviderElement< + AnyNotifier, void>, + AsyncValue, + Object?, + Object? + >; + element.handleValue(ref, null); + } +} diff --git a/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/providers/linked_devices_edit_mode_provider.dart b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/providers/linked_devices_edit_mode_provider.dart new file mode 100644 index 00000000..933e225c --- /dev/null +++ b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/providers/linked_devices_edit_mode_provider.dart @@ -0,0 +1,13 @@ +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'linked_devices_edit_mode_provider.g.dart'; + +@riverpod +class LinkedDevicesEditMode extends _$LinkedDevicesEditMode { + @override + bool build() => false; + + void toggle() => state = !state; + + void disable() => state = false; +} diff --git a/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/providers/linked_devices_edit_mode_provider.g.dart b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/providers/linked_devices_edit_mode_provider.g.dart new file mode 100644 index 00000000..5626c2f2 --- /dev/null +++ b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/providers/linked_devices_edit_mode_provider.g.dart @@ -0,0 +1,64 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'linked_devices_edit_mode_provider.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint, type=warning + +@ProviderFor(LinkedDevicesEditMode) +const linkedDevicesEditModeProvider = LinkedDevicesEditModeProvider._(); + +final class LinkedDevicesEditModeProvider + extends $NotifierProvider { + const LinkedDevicesEditModeProvider._() + : super( + from: null, + argument: null, + retry: null, + name: r'linkedDevicesEditModeProvider', + isAutoDispose: true, + dependencies: null, + $allTransitiveDependencies: null, + ); + + @override + String debugGetCreateSourceHash() => _$linkedDevicesEditModeHash(); + + @$internal + @override + LinkedDevicesEditMode create() => LinkedDevicesEditMode(); + + /// {@macro riverpod.override_with_value} + Override overrideWithValue(bool value) { + return $ProviderOverride( + origin: this, + providerOverride: $SyncValueProvider(value), + ); + } +} + +String _$linkedDevicesEditModeHash() => + r'aea2da0d62667e721fa059fe5b48201689bbf9c2'; + +abstract class _$LinkedDevicesEditMode extends $Notifier { + bool build(); + @$mustCallSuper + @override + void runBuild() { + final created = build(); + final ref = this.ref as $Ref; + final element = + ref.element + as $ClassProviderElement< + AnyNotifier, + bool, + Object?, + Object? + >; + element.handleValue(ref, created); + } +} diff --git a/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/state/linked_devices_view_model.dart b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/state/linked_devices_view_model.dart deleted file mode 100644 index da983bcf..00000000 --- a/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/state/linked_devices_view_model.dart +++ /dev/null @@ -1,132 +0,0 @@ -import 'dart:async'; - -import 'package:account/src/features/linked_devices/domain/entities/update_device_request_entity.dart'; -import 'package:account/src/features/linked_devices/presentation/state/linked_devices_view_state.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:sf_shared/sf_shared.dart'; -import 'package:sf_tracking/sf_tracking.dart'; - -import '../../../../core/domain/repositories/devices_repository.dart'; -import '../../../../core/providers/devices_repository_provider.dart'; - -final linkedDevicesViewModelProvider = - NotifierProvider.autoDispose< - LinkedDevicesViewModel, - LinkedDevicesViewState - >(LinkedDevicesViewModel.new); - -class LinkedDevicesViewModel extends Notifier { - late final SharedDevicesRepository _getDevicesRepository; - late final DevicesRepository _devicesRepository; - late final SfTrackingRepository _tracking; - - late final TextEditingController deviceNameController; - - @override - LinkedDevicesViewState build() { - _getDevicesRepository = ref.read(sharedDevicesRepositoryProvider); - _devicesRepository = ref.read(devicesRepositoryProvider); - _tracking = ref.read(sfTrackingProvider); - - _initControllers(); - _init(); - - return const LinkedDevicesViewState(); - } - - void _initControllers() { - deviceNameController = TextEditingController(); - deviceNameController.addListener(_onDeviceNameChanged); - - ref.onDispose(disposeControllers); - } - - Future _init() async { - final user = await ref.read(userInfoProvider.future); - state = state.copyWith(loggedUser: user); - - final linkedDevices = await _getDevicesRepository.getDevices(); - state = state.copyWith(linkedDevices: linkedDevices, isLoading: false); - } - - void toggleIsEditing() { - state = state.copyWith(isEditing: !state.isEditing); - } - - void _onDeviceNameChanged() { - final value = deviceNameController.text; - - if (value == state.deviceName) return; - - state = state.copyWith(deviceName: value); - } - - void setSelectedDevice(DeviceEntity value) { - if (value == state.selectedDevice) return; - - state = state.copyWith(selectedDevice: value); - } - - Future deleteDevice(DeviceEntity device) async { - try { - state = state.copyWith(isLoading: true, isComplete: false); - - await _devicesRepository.deleteDevice(deviceId: device.id); - List newList = state.linkedDevices.toList(); - newList.remove(device); - - if (device == state.selectedDevice) { - ref.invalidate(selectedDeviceProvider); - } - - ref.read(legacyDevicesProvider.notifier).removeDevice(device.id); - - unawaited(_tracking.legacyAccountLinkedDeviceUnlinked()); - - state = state.copyWith( - linkedDevices: newList, - isLoading: false, - isComplete: true, - ); - } catch (e) { - state = state.copyWith(isLoading: false, errorMessage: e.toString()); - return; - } - } - - UpdateDeviceRequestEntity _toRequest(DeviceEntity device) { - return UpdateDeviceRequestEntity( - identificator: device.identificator, - carrierName: state.deviceName.trim(), - // phone: /*state.dialCode.trim() + */state.phoneNumber.trim(), - ); - } - - Future updateDevice() async { - final deviceName = state.deviceName; - final device = state.selectedDevice!; - - if (deviceName.isEmpty) return; - - try { - await _devicesRepository.updateDevice(request: _toRequest(device)); - ref.read(legacyDevicesProvider.notifier).renameDevice( - deviceId: device.id, - newCarrierName: deviceName.trim(), - ); - unawaited(_tracking.legacyAccountLinkedDeviceRenamed()); - } catch (e) { - state = state.copyWith( - isLoading: false, - isComplete: false, - errorMessage: e.toString(), - ); - } - } - - void disposeControllers() { - deviceNameController.removeListener(_onDeviceNameChanged); - deviceNameController.dispose(); - } -} diff --git a/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/state/linked_devices_view_state.dart b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/state/linked_devices_view_state.dart deleted file mode 100644 index 477ee1c1..00000000 --- a/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/state/linked_devices_view_state.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:sf_shared/sf_shared.dart'; - -part 'linked_devices_view_state.freezed.dart'; - -@freezed -abstract class LinkedDevicesViewState with _$LinkedDevicesViewState { - const factory LinkedDevicesViewState({ - @Default(true) bool isLoading, - @Default(true) bool isComplete, - UserEntity? loggedUser, - DeviceEntity? selectedDevice, - @Default([]) List linkedDevices, - @Default(false) bool isEditing, - @Default('') String deviceName, - @Default('') String errorMessage, - }) = _LinkedDevicesViewState; -} diff --git a/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/state/linked_devices_view_state.freezed.dart b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/state/linked_devices_view_state.freezed.dart deleted file mode 100644 index 00339190..00000000 --- a/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/state/linked_devices_view_state.freezed.dart +++ /dev/null @@ -1,346 +0,0 @@ -// 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 'linked_devices_view_state.dart'; - -// ************************************************************************** -// FreezedGenerator -// ************************************************************************** - -// dart format off -T _$identity(T value) => value; -/// @nodoc -mixin _$LinkedDevicesViewState { - - bool get isLoading; bool get isComplete; UserEntity? get loggedUser; DeviceEntity? get selectedDevice; List get linkedDevices; bool get isEditing; String get deviceName; String get errorMessage; -/// Create a copy of LinkedDevicesViewState -/// with the given fields replaced by the non-null parameter values. -@JsonKey(includeFromJson: false, includeToJson: false) -@pragma('vm:prefer-inline') -$LinkedDevicesViewStateCopyWith get copyWith => _$LinkedDevicesViewStateCopyWithImpl(this as LinkedDevicesViewState, _$identity); - - - -@override -bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is LinkedDevicesViewState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isComplete, isComplete) || other.isComplete == isComplete)&&(identical(other.loggedUser, loggedUser) || other.loggedUser == loggedUser)&&(identical(other.selectedDevice, selectedDevice) || other.selectedDevice == selectedDevice)&&const DeepCollectionEquality().equals(other.linkedDevices, linkedDevices)&&(identical(other.isEditing, isEditing) || other.isEditing == isEditing)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)); -} - - -@override -int get hashCode => Object.hash(runtimeType,isLoading,isComplete,loggedUser,selectedDevice,const DeepCollectionEquality().hash(linkedDevices),isEditing,deviceName,errorMessage); - -@override -String toString() { - return 'LinkedDevicesViewState(isLoading: $isLoading, isComplete: $isComplete, loggedUser: $loggedUser, selectedDevice: $selectedDevice, linkedDevices: $linkedDevices, isEditing: $isEditing, deviceName: $deviceName, errorMessage: $errorMessage)'; -} - - -} - -/// @nodoc -abstract mixin class $LinkedDevicesViewStateCopyWith<$Res> { - factory $LinkedDevicesViewStateCopyWith(LinkedDevicesViewState value, $Res Function(LinkedDevicesViewState) _then) = _$LinkedDevicesViewStateCopyWithImpl; -@useResult -$Res call({ - bool isLoading, bool isComplete, UserEntity? loggedUser, DeviceEntity? selectedDevice, List linkedDevices, bool isEditing, String deviceName, String errorMessage -}); - - -$UserEntityCopyWith<$Res>? get loggedUser;$DeviceEntityCopyWith<$Res>? get selectedDevice; - -} -/// @nodoc -class _$LinkedDevicesViewStateCopyWithImpl<$Res> - implements $LinkedDevicesViewStateCopyWith<$Res> { - _$LinkedDevicesViewStateCopyWithImpl(this._self, this._then); - - final LinkedDevicesViewState _self; - final $Res Function(LinkedDevicesViewState) _then; - -/// Create a copy of LinkedDevicesViewState -/// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? isLoading = null,Object? isComplete = null,Object? loggedUser = freezed,Object? selectedDevice = freezed,Object? linkedDevices = null,Object? isEditing = null,Object? deviceName = null,Object? errorMessage = null,}) { - return _then(_self.copyWith( -isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable -as bool,isComplete: null == isComplete ? _self.isComplete : isComplete // ignore: cast_nullable_to_non_nullable -as bool,loggedUser: freezed == loggedUser ? _self.loggedUser : loggedUser // ignore: cast_nullable_to_non_nullable -as UserEntity?,selectedDevice: freezed == selectedDevice ? _self.selectedDevice : selectedDevice // ignore: cast_nullable_to_non_nullable -as DeviceEntity?,linkedDevices: null == linkedDevices ? _self.linkedDevices : linkedDevices // ignore: cast_nullable_to_non_nullable -as List,isEditing: null == isEditing ? _self.isEditing : isEditing // ignore: cast_nullable_to_non_nullable -as bool,deviceName: null == deviceName ? _self.deviceName : deviceName // ignore: cast_nullable_to_non_nullable -as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable -as String, - )); -} -/// Create a copy of LinkedDevicesViewState -/// with the given fields replaced by the non-null parameter values. -@override -@pragma('vm:prefer-inline') -$UserEntityCopyWith<$Res>? get loggedUser { - if (_self.loggedUser == null) { - return null; - } - - return $UserEntityCopyWith<$Res>(_self.loggedUser!, (value) { - return _then(_self.copyWith(loggedUser: value)); - }); -}/// Create a copy of LinkedDevicesViewState -/// with the given fields replaced by the non-null parameter values. -@override -@pragma('vm:prefer-inline') -$DeviceEntityCopyWith<$Res>? get selectedDevice { - if (_self.selectedDevice == null) { - return null; - } - - return $DeviceEntityCopyWith<$Res>(_self.selectedDevice!, (value) { - return _then(_self.copyWith(selectedDevice: value)); - }); -} -} - - -/// Adds pattern-matching-related methods to [LinkedDevicesViewState]. -extension LinkedDevicesViewStatePatterns on LinkedDevicesViewState { -/// 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( _LinkedDevicesViewState value)? $default,{required TResult orElse(),}){ -final _that = this; -switch (_that) { -case _LinkedDevicesViewState() 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( _LinkedDevicesViewState value) $default,){ -final _that = this; -switch (_that) { -case _LinkedDevicesViewState(): -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( _LinkedDevicesViewState value)? $default,){ -final _that = this; -switch (_that) { -case _LinkedDevicesViewState() 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( bool isLoading, bool isComplete, UserEntity? loggedUser, DeviceEntity? selectedDevice, List linkedDevices, bool isEditing, String deviceName, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this; -switch (_that) { -case _LinkedDevicesViewState() when $default != null: -return $default(_that.isLoading,_that.isComplete,_that.loggedUser,_that.selectedDevice,_that.linkedDevices,_that.isEditing,_that.deviceName,_that.errorMessage);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( bool isLoading, bool isComplete, UserEntity? loggedUser, DeviceEntity? selectedDevice, List linkedDevices, bool isEditing, String deviceName, String errorMessage) $default,) {final _that = this; -switch (_that) { -case _LinkedDevicesViewState(): -return $default(_that.isLoading,_that.isComplete,_that.loggedUser,_that.selectedDevice,_that.linkedDevices,_that.isEditing,_that.deviceName,_that.errorMessage);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( bool isLoading, bool isComplete, UserEntity? loggedUser, DeviceEntity? selectedDevice, List linkedDevices, bool isEditing, String deviceName, String errorMessage)? $default,) {final _that = this; -switch (_that) { -case _LinkedDevicesViewState() when $default != null: -return $default(_that.isLoading,_that.isComplete,_that.loggedUser,_that.selectedDevice,_that.linkedDevices,_that.isEditing,_that.deviceName,_that.errorMessage);case _: - return null; - -} -} - -} - -/// @nodoc - - -class _LinkedDevicesViewState implements LinkedDevicesViewState { - const _LinkedDevicesViewState({this.isLoading = true, this.isComplete = true, this.loggedUser, this.selectedDevice, final List linkedDevices = const [], this.isEditing = false, this.deviceName = '', this.errorMessage = ''}): _linkedDevices = linkedDevices; - - -@override@JsonKey() final bool isLoading; -@override@JsonKey() final bool isComplete; -@override final UserEntity? loggedUser; -@override final DeviceEntity? selectedDevice; - final List _linkedDevices; -@override@JsonKey() List get linkedDevices { - if (_linkedDevices is EqualUnmodifiableListView) return _linkedDevices; - // ignore: implicit_dynamic_type - return EqualUnmodifiableListView(_linkedDevices); -} - -@override@JsonKey() final bool isEditing; -@override@JsonKey() final String deviceName; -@override@JsonKey() final String errorMessage; - -/// Create a copy of LinkedDevicesViewState -/// with the given fields replaced by the non-null parameter values. -@override @JsonKey(includeFromJson: false, includeToJson: false) -@pragma('vm:prefer-inline') -_$LinkedDevicesViewStateCopyWith<_LinkedDevicesViewState> get copyWith => __$LinkedDevicesViewStateCopyWithImpl<_LinkedDevicesViewState>(this, _$identity); - - - -@override -bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _LinkedDevicesViewState&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isComplete, isComplete) || other.isComplete == isComplete)&&(identical(other.loggedUser, loggedUser) || other.loggedUser == loggedUser)&&(identical(other.selectedDevice, selectedDevice) || other.selectedDevice == selectedDevice)&&const DeepCollectionEquality().equals(other._linkedDevices, _linkedDevices)&&(identical(other.isEditing, isEditing) || other.isEditing == isEditing)&&(identical(other.deviceName, deviceName) || other.deviceName == deviceName)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)); -} - - -@override -int get hashCode => Object.hash(runtimeType,isLoading,isComplete,loggedUser,selectedDevice,const DeepCollectionEquality().hash(_linkedDevices),isEditing,deviceName,errorMessage); - -@override -String toString() { - return 'LinkedDevicesViewState(isLoading: $isLoading, isComplete: $isComplete, loggedUser: $loggedUser, selectedDevice: $selectedDevice, linkedDevices: $linkedDevices, isEditing: $isEditing, deviceName: $deviceName, errorMessage: $errorMessage)'; -} - - -} - -/// @nodoc -abstract mixin class _$LinkedDevicesViewStateCopyWith<$Res> implements $LinkedDevicesViewStateCopyWith<$Res> { - factory _$LinkedDevicesViewStateCopyWith(_LinkedDevicesViewState value, $Res Function(_LinkedDevicesViewState) _then) = __$LinkedDevicesViewStateCopyWithImpl; -@override @useResult -$Res call({ - bool isLoading, bool isComplete, UserEntity? loggedUser, DeviceEntity? selectedDevice, List linkedDevices, bool isEditing, String deviceName, String errorMessage -}); - - -@override $UserEntityCopyWith<$Res>? get loggedUser;@override $DeviceEntityCopyWith<$Res>? get selectedDevice; - -} -/// @nodoc -class __$LinkedDevicesViewStateCopyWithImpl<$Res> - implements _$LinkedDevicesViewStateCopyWith<$Res> { - __$LinkedDevicesViewStateCopyWithImpl(this._self, this._then); - - final _LinkedDevicesViewState _self; - final $Res Function(_LinkedDevicesViewState) _then; - -/// Create a copy of LinkedDevicesViewState -/// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? isLoading = null,Object? isComplete = null,Object? loggedUser = freezed,Object? selectedDevice = freezed,Object? linkedDevices = null,Object? isEditing = null,Object? deviceName = null,Object? errorMessage = null,}) { - return _then(_LinkedDevicesViewState( -isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable -as bool,isComplete: null == isComplete ? _self.isComplete : isComplete // ignore: cast_nullable_to_non_nullable -as bool,loggedUser: freezed == loggedUser ? _self.loggedUser : loggedUser // ignore: cast_nullable_to_non_nullable -as UserEntity?,selectedDevice: freezed == selectedDevice ? _self.selectedDevice : selectedDevice // ignore: cast_nullable_to_non_nullable -as DeviceEntity?,linkedDevices: null == linkedDevices ? _self._linkedDevices : linkedDevices // ignore: cast_nullable_to_non_nullable -as List,isEditing: null == isEditing ? _self.isEditing : isEditing // ignore: cast_nullable_to_non_nullable -as bool,deviceName: null == deviceName ? _self.deviceName : deviceName // ignore: cast_nullable_to_non_nullable -as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable -as String, - )); -} - -/// Create a copy of LinkedDevicesViewState -/// with the given fields replaced by the non-null parameter values. -@override -@pragma('vm:prefer-inline') -$UserEntityCopyWith<$Res>? get loggedUser { - if (_self.loggedUser == null) { - return null; - } - - return $UserEntityCopyWith<$Res>(_self.loggedUser!, (value) { - return _then(_self.copyWith(loggedUser: value)); - }); -}/// Create a copy of LinkedDevicesViewState -/// with the given fields replaced by the non-null parameter values. -@override -@pragma('vm:prefer-inline') -$DeviceEntityCopyWith<$Res>? get selectedDevice { - if (_self.selectedDevice == null) { - return null; - } - - return $DeviceEntityCopyWith<$Res>(_self.selectedDevice!, (value) { - return _then(_self.copyWith(selectedDevice: value)); - }); -} -} - -// dart format on diff --git a/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/widgets/delete_device_dialog.dart b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/widgets/delete_device_dialog.dart index 27ea5f5a..1645b513 100644 --- a/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/widgets/delete_device_dialog.dart +++ b/modules/legacy/modules/account/lib/src/features/linked_devices/presentation/widgets/delete_device_dialog.dart @@ -1,32 +1,23 @@ -import 'package:account/src/features/linked_devices/presentation/state/linked_devices_view_model.dart'; +import 'package:account/src/features/linked_devices/presentation/providers/linked_devices_controller.dart'; import 'package:design_system/design_system.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:navigation/navigation.dart'; +import 'package:legacy_theme/legacy_theme.dart'; import 'package:sf_localizations/sf_localizations.dart'; import 'package:sf_shared/sf_shared.dart'; import 'package:utils/utils.dart'; -import 'package:legacy_theme/legacy_theme.dart'; class DeleteDeviceDialog extends ConsumerWidget { - final NavigationContract navigationContract; final DeviceEntity device; - const DeleteDeviceDialog({ - super.key, - required this.navigationContract, - required this.device, - }); + const DeleteDeviceDialog({super.key, required this.device}); @override Widget build(BuildContext context, WidgetRef ref) { - - final vm = ref.read(linkedDevicesViewModelProvider.notifier); - return Container( padding: SizeUtils.getByScreen( - small: EdgeInsets.symmetric(horizontal: 32, vertical: 30), - big: EdgeInsets.symmetric(horizontal: 24, vertical: 18), + small: const EdgeInsets.symmetric(horizontal: 32, vertical: 30), + big: const EdgeInsets.symmetric(horizontal: 24, vertical: 18), ), width: SizeUtils.getByScreen(small: 360, big: 350), child: Column( @@ -45,9 +36,7 @@ class DeleteDeviceDialog extends ConsumerWidget { children: [ Expanded( child: PrimaryButton( - onPressed: () { - Navigator.pop(context); - }, + onPressed: () => Navigator.pop(context), text: context.translate(I18n.cancel), color: context.sfColors.legacyPrimary, height: SizeUtils.getByScreen(small: 38, big: 36), @@ -57,29 +46,11 @@ class DeleteDeviceDialog extends ConsumerWidget { SizedBox(width: SizeUtils.getByScreen(small: 4, big: 16)), Expanded( child: PrimaryButton( - onPressed: () async { - await vm.deleteDevice(device); - if (!context.mounted) return; - - final isComplete = ref.read( - linkedDevicesViewModelProvider.select( - (s) => s.isComplete, - ), - ); - if (isComplete) { - Navigator.pop(context); - } - - final noMoreDevices = ref - .read( - linkedDevicesViewModelProvider.select( - (s) => s.linkedDevices, - ), - ) - .isEmpty; - if (noMoreDevices) { - navigationContract.goTo(AppRoutes.legacyDeviceSetup); - } + onPressed: () { + Navigator.pop(context); + ref + .read(linkedDevicesControllerProvider.notifier) + .deleteDevice(device); }, text: context.translate(I18n.delete), color: context.sfColors.legacyPrimary, diff --git a/modules/legacy/modules/account/test/features/linked_devices/linked_devices_controller_test.dart b/modules/legacy/modules/account/test/features/linked_devices/linked_devices_controller_test.dart new file mode 100644 index 00000000..a6a6462a --- /dev/null +++ b/modules/legacy/modules/account/test/features/linked_devices/linked_devices_controller_test.dart @@ -0,0 +1,145 @@ +import 'package:account/src/core/domain/repositories/devices_repository.dart'; +import 'package:account/src/core/providers/devices_repository_provider.dart'; +import 'package:account/src/features/linked_devices/presentation/providers/linked_devices_controller.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:sf_infrastructure/sf_infrastructure.dart'; +import 'package:sf_shared/sf_shared.dart'; +import 'package:sf_shared/testing.dart'; +import 'package:sf_tracking/sf_tracking.dart'; + +class MockDevicesRepository extends Mock implements DevicesRepository {} + +class MockSharedDevicesRepository extends Mock + implements SharedDevicesRepository {} + +const _deviceA = DeviceEntity( + id: 'device-A', + identificator: 'imei-A', + carrierName: 'Alice Watch', + phone: '+34600000001', +); + +const _deviceB = DeviceEntity( + id: 'device-B', + identificator: 'imei-B', + carrierName: 'Bob Watch', + phone: '+34600000002', +); + +void main() { + setUpAll(() { + registerFallbackValue(_deviceA); + }); + + ProviderContainer buildContainer({ + required DevicesRepository devicesRepo, + List initialDevices = const [_deviceA, _deviceB], + }) { + final shared = MockSharedDevicesRepository(); + when(() => shared.getDevices()).thenAnswer((_) async => initialDevices); + + return makeContainer( + overrides: [ + sharedDevicesRepositoryProvider.overrideWithValue(shared), + devicesRepositoryProvider.overrideWithValue(devicesRepo), + sfTrackingProvider.overrideWithValue( + SfTrackingRepository(clients: const []), + ), + ], + ); + } + + group('LinkedDevicesController.deleteDevice', () { + test('removes device from legacyDevicesProvider on success', () async { + final repo = MockDevicesRepository(); + when(() => repo.deleteDevice(deviceId: any(named: 'deviceId'))) + .thenAnswer((_) async {}); + + final container = buildContainer(devicesRepo: repo); + addTearDown(container.dispose); + await container.read(legacyDevicesProvider.future); + + await container + .read(linkedDevicesControllerProvider.notifier) + .deleteDevice(_deviceA); + + final state = container.read(linkedDevicesControllerProvider); + expect(state, isA>()); + expect(state.error, isNull); + + final remaining = container.read(legacyDevicesProvider).value; + expect(remaining, [_deviceB]); + + verify(() => repo.deleteDevice(deviceId: 'device-A')).called(1); + }); + + test('exposes AsyncError when the repository fails', () async { + final repo = MockDevicesRepository(); + when(() => repo.deleteDevice(deviceId: any(named: 'deviceId'))) + .thenThrow(const ApiException(message: 'boom', isNetworkError: true)); + + final container = buildContainer(devicesRepo: repo); + addTearDown(container.dispose); + await container.read(legacyDevicesProvider.future); + + await container + .read(linkedDevicesControllerProvider.notifier) + .deleteDevice(_deviceA); + + final state = container.read(linkedDevicesControllerProvider); + expect(state, isA>()); + expect(state.error, isA()); + }); + }); + + group('LinkedDevicesController.updateDevice', () { + test('renames device in legacyDevicesProvider on success', () async { + final repo = MockDevicesRepository(); + when(() => repo.updateDevice(device: any(named: 'device'))) + .thenAnswer((_) async {}); + + final container = buildContainer(devicesRepo: repo); + addTearDown(container.dispose); + await container.read(legacyDevicesProvider.future); + + await container + .read(linkedDevicesControllerProvider.notifier) + .updateDevice(device: _deviceA, newName: 'Alice Sport'); + + final state = container.read(linkedDevicesControllerProvider); + expect(state, isA>()); + + final devices = container.read(legacyDevicesProvider).value!; + expect(devices.firstWhere((d) => d.id == 'device-A').carrierName, + 'Alice Sport'); + expect(devices.firstWhere((d) => d.id == 'device-B').carrierName, + 'Bob Watch'); + + final captured = verify( + () => repo.updateDevice(device: captureAny(named: 'device')), + ).captured.single as DeviceEntity; + expect(captured.id, 'device-A'); + expect(captured.carrierName, 'Alice Sport'); + }); + + test('exposes AsyncError when the repository fails', () async { + final repo = MockDevicesRepository(); + when(() => repo.updateDevice(device: any(named: 'device'))) + .thenThrow(const ApiException(message: 'boom', isNetworkError: true)); + + final container = buildContainer(devicesRepo: repo); + addTearDown(container.dispose); + await container.read(legacyDevicesProvider.future); + + await container + .read(linkedDevicesControllerProvider.notifier) + .updateDevice(device: _deviceA, newName: 'Alice Sport'); + + final state = container.read(linkedDevicesControllerProvider); + expect(state, isA>()); + expect(state.error, isA()); + }); + }); +} diff --git a/modules/legacy/modules/account/test/features/linked_devices/linked_devices_edit_mode_test.dart b/modules/legacy/modules/account/test/features/linked_devices/linked_devices_edit_mode_test.dart new file mode 100644 index 00000000..a3f6089e --- /dev/null +++ b/modules/legacy/modules/account/test/features/linked_devices/linked_devices_edit_mode_test.dart @@ -0,0 +1,47 @@ +import 'package:account/src/features/linked_devices/presentation/providers/linked_devices_edit_mode_provider.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:sf_shared/testing.dart'; + +void main() { + group('LinkedDevicesEditMode', () { + test('defaults to false', () { + final container = makeContainer(); + addTearDown(container.dispose); + + expect(container.read(linkedDevicesEditModeProvider), isFalse); + }); + + test('toggle flips the state', () { + final container = makeContainer(); + addTearDown(container.dispose); + + final notifier = container.read( + linkedDevicesEditModeProvider.notifier, + ); + + notifier.toggle(); + expect(container.read(linkedDevicesEditModeProvider), isTrue); + + notifier.toggle(); + expect(container.read(linkedDevicesEditModeProvider), isFalse); + }); + + test('disable forces state to false regardless of current value', () { + final container = makeContainer(); + addTearDown(container.dispose); + + final notifier = container.read( + linkedDevicesEditModeProvider.notifier, + ); + + notifier.disable(); + expect(container.read(linkedDevicesEditModeProvider), isFalse); + + notifier.toggle(); + expect(container.read(linkedDevicesEditModeProvider), isTrue); + + notifier.disable(); + expect(container.read(linkedDevicesEditModeProvider), isFalse); + }); + }); +}