refactor(device-management): migrate call_watch and remote_connection to SfPhoneNumber

This commit is contained in:
2026-04-15 17:06:41 +02:00
parent 88c1111bd5
commit 56e437ff13
15 changed files with 119 additions and 87 deletions

View File

@@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:device_management/src/features/device_management/state/call_watch_view_state.dart';
import 'package:sf_localizations/sf_localizations.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:url_launcher/url_launcher.dart';
final callWatchViewModelProvider =
@@ -11,15 +13,12 @@ final callWatchViewModelProvider =
class CallWatchViewModel extends Notifier<CallWatchViewState> {
late final TextEditingController phoneController;
static final RegExp _phoneRegex = RegExp(r'^\+?\d{6,15}$');
@override
CallWatchViewState build() {
phoneController = TextEditingController();
phoneController.addListener(_onPhoneChanged);
ref.onDispose(disposeControllers);
ref.onDispose(_disposeControllers);
return const CallWatchViewState();
}
@@ -27,27 +26,28 @@ class CallWatchViewModel extends Notifier<CallWatchViewState> {
void _onPhoneChanged() {
final text = phoneController.text;
if (text == state.phone) return;
state = state.copyWith(phone: text, errorMessage: '');
}
void updateDialCode(String code) {
state = state.copyWith(dialCode: code, errorMessage: '');
void updateCountry(String isoCode) {
if (isoCode == state.isoCode) return;
state = state.copyWith(isoCode: isoCode, errorMessage: '');
}
void call() async {
final phone = state.phone;
Future<void> call() async {
final phone = state.phone.trim();
if (phone.isEmpty) {
state = state.copyWith(errorMessage: 'errorMessagePhoneIsEmpty');
return;
}
if (!_phoneRegex.hasMatch(phone)) {
state = state.copyWith(errorMessage: 'errorMessagePhoneIsInvalid');
state = state.copyWith(errorMessage: I18n.errorMessagePhoneIsEmpty);
return;
}
final fullNumber = '${state.dialCode}$phone';
final url = Uri(scheme: 'tel', path: fullNumber);
final parsed = SfPhoneNumber.tryParse(phone, defaultIsoCode: state.isoCode);
if (parsed == null) {
state = state.copyWith(errorMessage: I18n.errorMessagePhoneIsInvalid);
return;
}
final url = Uri(scheme: 'tel', path: parsed.e164);
if (await canLaunchUrl(url)) {
launchUrl(url);
@@ -56,9 +56,8 @@ class CallWatchViewModel extends Notifier<CallWatchViewState> {
}
}
void disposeControllers() {
void _disposeControllers() {
phoneController.removeListener(_onPhoneChanged);
phoneController.dispose();
}
}

View File

@@ -5,7 +5,7 @@ part 'call_watch_view_state.freezed.dart';
@freezed
abstract class CallWatchViewState with _$CallWatchViewState {
const factory CallWatchViewState({
@Default('+34') String dialCode,
@Default('ES') String isoCode,
@Default('') String phone,
@Default('') String errorMessage,
}) = _CallWatchViewState;

View File

@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
/// @nodoc
mixin _$CallWatchViewState {
String get dialCode; String get phone; String get errorMessage;
String get isoCode; String get phone; String get errorMessage;
/// Create a copy of CallWatchViewState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -25,16 +25,16 @@ $CallWatchViewStateCopyWith<CallWatchViewState> get copyWith => _$CallWatchViewS
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is CallWatchViewState&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.phone, phone) || other.phone == phone)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
return identical(this, other) || (other.runtimeType == runtimeType&&other is CallWatchViewState&&(identical(other.isoCode, isoCode) || other.isoCode == isoCode)&&(identical(other.phone, phone) || other.phone == phone)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
}
@override
int get hashCode => Object.hash(runtimeType,dialCode,phone,errorMessage);
int get hashCode => Object.hash(runtimeType,isoCode,phone,errorMessage);
@override
String toString() {
return 'CallWatchViewState(dialCode: $dialCode, phone: $phone, errorMessage: $errorMessage)';
return 'CallWatchViewState(isoCode: $isoCode, phone: $phone, errorMessage: $errorMessage)';
}
@@ -45,7 +45,7 @@ abstract mixin class $CallWatchViewStateCopyWith<$Res> {
factory $CallWatchViewStateCopyWith(CallWatchViewState value, $Res Function(CallWatchViewState) _then) = _$CallWatchViewStateCopyWithImpl;
@useResult
$Res call({
String dialCode, String phone, String errorMessage
String isoCode, String phone, String errorMessage
});
@@ -62,9 +62,9 @@ class _$CallWatchViewStateCopyWithImpl<$Res>
/// Create a copy of CallWatchViewState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? dialCode = null,Object? phone = null,Object? errorMessage = null,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? isoCode = null,Object? phone = null,Object? errorMessage = null,}) {
return _then(_self.copyWith(
dialCode: null == dialCode ? _self.dialCode : dialCode // ignore: cast_nullable_to_non_nullable
isoCode: null == isoCode ? _self.isoCode : isoCode // ignore: cast_nullable_to_non_nullable
as String,phone: null == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable
as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
as String,
@@ -152,10 +152,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String dialCode, String phone, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String isoCode, String phone, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _CallWatchViewState() when $default != null:
return $default(_that.dialCode,_that.phone,_that.errorMessage);case _:
return $default(_that.isoCode,_that.phone,_that.errorMessage);case _:
return orElse();
}
@@ -173,10 +173,10 @@ return $default(_that.dialCode,_that.phone,_that.errorMessage);case _:
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String dialCode, String phone, String errorMessage) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String isoCode, String phone, String errorMessage) $default,) {final _that = this;
switch (_that) {
case _CallWatchViewState():
return $default(_that.dialCode,_that.phone,_that.errorMessage);case _:
return $default(_that.isoCode,_that.phone,_that.errorMessage);case _:
throw StateError('Unexpected subclass');
}
@@ -193,10 +193,10 @@ return $default(_that.dialCode,_that.phone,_that.errorMessage);case _:
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String dialCode, String phone, String errorMessage)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String isoCode, String phone, String errorMessage)? $default,) {final _that = this;
switch (_that) {
case _CallWatchViewState() when $default != null:
return $default(_that.dialCode,_that.phone,_that.errorMessage);case _:
return $default(_that.isoCode,_that.phone,_that.errorMessage);case _:
return null;
}
@@ -208,10 +208,10 @@ return $default(_that.dialCode,_that.phone,_that.errorMessage);case _:
class _CallWatchViewState implements CallWatchViewState {
const _CallWatchViewState({this.dialCode = '+34', this.phone = '', this.errorMessage = ''});
const _CallWatchViewState({this.isoCode = 'ES', this.phone = '', this.errorMessage = ''});
@override@JsonKey() final String dialCode;
@override@JsonKey() final String isoCode;
@override@JsonKey() final String phone;
@override@JsonKey() final String errorMessage;
@@ -225,16 +225,16 @@ _$CallWatchViewStateCopyWith<_CallWatchViewState> get copyWith => __$CallWatchVi
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CallWatchViewState&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.phone, phone) || other.phone == phone)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CallWatchViewState&&(identical(other.isoCode, isoCode) || other.isoCode == isoCode)&&(identical(other.phone, phone) || other.phone == phone)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage));
}
@override
int get hashCode => Object.hash(runtimeType,dialCode,phone,errorMessage);
int get hashCode => Object.hash(runtimeType,isoCode,phone,errorMessage);
@override
String toString() {
return 'CallWatchViewState(dialCode: $dialCode, phone: $phone, errorMessage: $errorMessage)';
return 'CallWatchViewState(isoCode: $isoCode, phone: $phone, errorMessage: $errorMessage)';
}
@@ -245,7 +245,7 @@ abstract mixin class _$CallWatchViewStateCopyWith<$Res> implements $CallWatchVie
factory _$CallWatchViewStateCopyWith(_CallWatchViewState value, $Res Function(_CallWatchViewState) _then) = __$CallWatchViewStateCopyWithImpl;
@override @useResult
$Res call({
String dialCode, String phone, String errorMessage
String isoCode, String phone, String errorMessage
});
@@ -262,9 +262,9 @@ class __$CallWatchViewStateCopyWithImpl<$Res>
/// Create a copy of CallWatchViewState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? dialCode = null,Object? phone = null,Object? errorMessage = null,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? isoCode = null,Object? phone = null,Object? errorMessage = null,}) {
return _then(_CallWatchViewState(
dialCode: null == dialCode ? _self.dialCode : dialCode // ignore: cast_nullable_to_non_nullable
isoCode: null == isoCode ? _self.isoCode : isoCode // ignore: cast_nullable_to_non_nullable
as String,phone: null == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable
as String,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable
as String,

View File

@@ -21,8 +21,8 @@ class CallWatchDialog extends ConsumerWidget {
big: EdgeInsets.symmetric(horizontal: 24, vertical: 18),
),
width: SizeUtils.getByScreen(small: 390, big: 380),
height: SizeUtils.getByScreen(small: 250, big: 243),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Stack(
children: [
@@ -50,16 +50,24 @@ class CallWatchDialog extends ConsumerWidget {
],
),
SizedBox(height: SizeUtils.getByScreen(small: 8, big: 7)),
Text(
context.translate(I18n.callWatchSubtitle),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: SizeUtils.getByScreen(small: 13, big: 12),
color: Colors.black54,
),
),
SizedBox(height: SizeUtils.getByScreen(small: 12, big: 10)),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CountryPrefixPicker(
headerText: context.translate(I18n.selectYourCountry),
initialSelection: viewState.dialCode,
initialSelection: viewState.isoCode,
onChanged: (country) {
viewModel.updateDialCode(
country.dialCode ?? viewState.dialCode,
);
final code = country.code;
if (code != null) viewModel.updateCountry(code);
},
width: 80,
backgroundColor: Colors.transparent,
@@ -79,7 +87,7 @@ class CallWatchDialog extends ConsumerWidget {
Padding(
padding: const EdgeInsets.only(top: 12),
child: Text(
viewState.errorMessage,
context.translate(viewState.errorMessage),
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).colorScheme.error,

View File

@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:device_management/src/features/remote_connection/presentation/state/remote_connection_view_state.dart';
import 'package:legacy_shared/legacy_shared.dart';
import 'package:sf_shared/sf_shared.dart';
import 'package:sf_tracking/sf_tracking.dart';
import '../../../../core/domain/repositories/pictures_repository.dart';
@@ -22,7 +23,6 @@ class RemoteConnectionViewModel extends Notifier<RemoteConnectionViewState> {
late final SfTrackingRepository _tracking;
Timer? _photoTimer;
static final RegExp _phoneRegex = RegExp(r'^\+?\d{6,15}$');
static const int _photoWaitSeconds = 5;
@override
@@ -69,9 +69,9 @@ class RemoteConnectionViewModel extends Notifier<RemoteConnectionViewState> {
state = state.copyWith(phone: text, errorEvent: null);
}
void updateDialCode(String value) {
if (value == state.dialCode) return;
state = state.copyWith(dialCode: value, errorEvent: null);
void updateCountry(String isoCode) {
if (isoCode == state.isoCode) return;
state = state.copyWith(isoCode: isoCode, errorEvent: null);
}
void prevPicture() {
@@ -177,9 +177,11 @@ class RemoteConnectionViewModel extends Notifier<RemoteConnectionViewState> {
}
Future<void> call() async {
final phone = phoneController.text;
final dialCode = state.dialCode;
if (phone.isEmpty || !_phoneRegex.hasMatch(phone)) {
final parsed = SfPhoneNumber.tryParse(
phoneController.text,
defaultIsoCode: state.isoCode,
);
if (parsed == null) {
state = state.copyWith(
errorEvent: RemoteConnectionErrorEvent.invalidPhone,
);
@@ -189,11 +191,10 @@ class RemoteConnectionViewModel extends Notifier<RemoteConnectionViewState> {
try {
state = state.copyWith(isCalling: true);
final fullPhone = dialCode + phone;
final request = SendCommandRequestModel(
device: state.deviceId,
command: DeviceCommand.callCenter,
data: {'phone_number': fullPhone},
data: {'phone_number': parsed.e164},
);
await _commandsRepository.send(request: request);

View File

@@ -11,7 +11,7 @@ enum RemoteConnectionSuccessEvent { photoTaken }
abstract class RemoteConnectionViewState with _$RemoteConnectionViewState {
const factory RemoteConnectionViewState({
@Default('') String deviceId,
@Default('+34') String dialCode,
@Default('ES') String isoCode,
@Default('') String phone,
@Default([]) List<PictureEntity> pictures,
@Default(0) int pictureIndex,

View File

@@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
/// @nodoc
mixin _$RemoteConnectionViewState {
String get deviceId; String get dialCode; String get phone; List<PictureEntity> get pictures; int get pictureIndex; bool get isLoadingPictures; bool get isTakingPicture; bool get isWaitingForPhoto; int get photoCountdown; bool get isCalling; RemoteConnectionErrorEvent? get errorEvent; RemoteConnectionSuccessEvent? get successEvent;
String get deviceId; String get isoCode; String get phone; List<PictureEntity> get pictures; int get pictureIndex; bool get isLoadingPictures; bool get isTakingPicture; bool get isWaitingForPhoto; int get photoCountdown; bool get isCalling; RemoteConnectionErrorEvent? get errorEvent; RemoteConnectionSuccessEvent? get successEvent;
/// Create a copy of RemoteConnectionViewState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@@ -25,16 +25,16 @@ $RemoteConnectionViewStateCopyWith<RemoteConnectionViewState> get copyWith => _$
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is RemoteConnectionViewState&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.phone, phone) || other.phone == phone)&&const DeepCollectionEquality().equals(other.pictures, pictures)&&(identical(other.pictureIndex, pictureIndex) || other.pictureIndex == pictureIndex)&&(identical(other.isLoadingPictures, isLoadingPictures) || other.isLoadingPictures == isLoadingPictures)&&(identical(other.isTakingPicture, isTakingPicture) || other.isTakingPicture == isTakingPicture)&&(identical(other.isWaitingForPhoto, isWaitingForPhoto) || other.isWaitingForPhoto == isWaitingForPhoto)&&(identical(other.photoCountdown, photoCountdown) || other.photoCountdown == photoCountdown)&&(identical(other.isCalling, isCalling) || other.isCalling == isCalling)&&(identical(other.errorEvent, errorEvent) || other.errorEvent == errorEvent)&&(identical(other.successEvent, successEvent) || other.successEvent == successEvent));
return identical(this, other) || (other.runtimeType == runtimeType&&other is RemoteConnectionViewState&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.isoCode, isoCode) || other.isoCode == isoCode)&&(identical(other.phone, phone) || other.phone == phone)&&const DeepCollectionEquality().equals(other.pictures, pictures)&&(identical(other.pictureIndex, pictureIndex) || other.pictureIndex == pictureIndex)&&(identical(other.isLoadingPictures, isLoadingPictures) || other.isLoadingPictures == isLoadingPictures)&&(identical(other.isTakingPicture, isTakingPicture) || other.isTakingPicture == isTakingPicture)&&(identical(other.isWaitingForPhoto, isWaitingForPhoto) || other.isWaitingForPhoto == isWaitingForPhoto)&&(identical(other.photoCountdown, photoCountdown) || other.photoCountdown == photoCountdown)&&(identical(other.isCalling, isCalling) || other.isCalling == isCalling)&&(identical(other.errorEvent, errorEvent) || other.errorEvent == errorEvent)&&(identical(other.successEvent, successEvent) || other.successEvent == successEvent));
}
@override
int get hashCode => Object.hash(runtimeType,deviceId,dialCode,phone,const DeepCollectionEquality().hash(pictures),pictureIndex,isLoadingPictures,isTakingPicture,isWaitingForPhoto,photoCountdown,isCalling,errorEvent,successEvent);
int get hashCode => Object.hash(runtimeType,deviceId,isoCode,phone,const DeepCollectionEquality().hash(pictures),pictureIndex,isLoadingPictures,isTakingPicture,isWaitingForPhoto,photoCountdown,isCalling,errorEvent,successEvent);
@override
String toString() {
return 'RemoteConnectionViewState(deviceId: $deviceId, dialCode: $dialCode, phone: $phone, pictures: $pictures, pictureIndex: $pictureIndex, isLoadingPictures: $isLoadingPictures, isTakingPicture: $isTakingPicture, isWaitingForPhoto: $isWaitingForPhoto, photoCountdown: $photoCountdown, isCalling: $isCalling, errorEvent: $errorEvent, successEvent: $successEvent)';
return 'RemoteConnectionViewState(deviceId: $deviceId, isoCode: $isoCode, phone: $phone, pictures: $pictures, pictureIndex: $pictureIndex, isLoadingPictures: $isLoadingPictures, isTakingPicture: $isTakingPicture, isWaitingForPhoto: $isWaitingForPhoto, photoCountdown: $photoCountdown, isCalling: $isCalling, errorEvent: $errorEvent, successEvent: $successEvent)';
}
@@ -45,7 +45,7 @@ abstract mixin class $RemoteConnectionViewStateCopyWith<$Res> {
factory $RemoteConnectionViewStateCopyWith(RemoteConnectionViewState value, $Res Function(RemoteConnectionViewState) _then) = _$RemoteConnectionViewStateCopyWithImpl;
@useResult
$Res call({
String deviceId, String dialCode, String phone, List<PictureEntity> pictures, int pictureIndex, bool isLoadingPictures, bool isTakingPicture, bool isWaitingForPhoto, int photoCountdown, bool isCalling, RemoteConnectionErrorEvent? errorEvent, RemoteConnectionSuccessEvent? successEvent
String deviceId, String isoCode, String phone, List<PictureEntity> pictures, int pictureIndex, bool isLoadingPictures, bool isTakingPicture, bool isWaitingForPhoto, int photoCountdown, bool isCalling, RemoteConnectionErrorEvent? errorEvent, RemoteConnectionSuccessEvent? successEvent
});
@@ -62,10 +62,10 @@ class _$RemoteConnectionViewStateCopyWithImpl<$Res>
/// Create a copy of RemoteConnectionViewState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? deviceId = null,Object? dialCode = null,Object? phone = null,Object? pictures = null,Object? pictureIndex = null,Object? isLoadingPictures = null,Object? isTakingPicture = null,Object? isWaitingForPhoto = null,Object? photoCountdown = null,Object? isCalling = null,Object? errorEvent = freezed,Object? successEvent = freezed,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? deviceId = null,Object? isoCode = null,Object? phone = null,Object? pictures = null,Object? pictureIndex = null,Object? isLoadingPictures = null,Object? isTakingPicture = null,Object? isWaitingForPhoto = null,Object? photoCountdown = null,Object? isCalling = null,Object? errorEvent = freezed,Object? successEvent = freezed,}) {
return _then(_self.copyWith(
deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
as String,dialCode: null == dialCode ? _self.dialCode : dialCode // ignore: cast_nullable_to_non_nullable
as String,isoCode: null == isoCode ? _self.isoCode : isoCode // ignore: cast_nullable_to_non_nullable
as String,phone: null == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable
as String,pictures: null == pictures ? _self.pictures : pictures // ignore: cast_nullable_to_non_nullable
as List<PictureEntity>,pictureIndex: null == pictureIndex ? _self.pictureIndex : pictureIndex // ignore: cast_nullable_to_non_nullable
@@ -161,10 +161,10 @@ return $default(_that);case _:
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String deviceId, String dialCode, String phone, List<PictureEntity> pictures, int pictureIndex, bool isLoadingPictures, bool isTakingPicture, bool isWaitingForPhoto, int photoCountdown, bool isCalling, RemoteConnectionErrorEvent? errorEvent, RemoteConnectionSuccessEvent? successEvent)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String deviceId, String isoCode, String phone, List<PictureEntity> pictures, int pictureIndex, bool isLoadingPictures, bool isTakingPicture, bool isWaitingForPhoto, int photoCountdown, bool isCalling, RemoteConnectionErrorEvent? errorEvent, RemoteConnectionSuccessEvent? successEvent)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _RemoteConnectionViewState() when $default != null:
return $default(_that.deviceId,_that.dialCode,_that.phone,_that.pictures,_that.pictureIndex,_that.isLoadingPictures,_that.isTakingPicture,_that.isWaitingForPhoto,_that.photoCountdown,_that.isCalling,_that.errorEvent,_that.successEvent);case _:
return $default(_that.deviceId,_that.isoCode,_that.phone,_that.pictures,_that.pictureIndex,_that.isLoadingPictures,_that.isTakingPicture,_that.isWaitingForPhoto,_that.photoCountdown,_that.isCalling,_that.errorEvent,_that.successEvent);case _:
return orElse();
}
@@ -182,10 +182,10 @@ return $default(_that.deviceId,_that.dialCode,_that.phone,_that.pictures,_that.p
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String deviceId, String dialCode, String phone, List<PictureEntity> pictures, int pictureIndex, bool isLoadingPictures, bool isTakingPicture, bool isWaitingForPhoto, int photoCountdown, bool isCalling, RemoteConnectionErrorEvent? errorEvent, RemoteConnectionSuccessEvent? successEvent) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String deviceId, String isoCode, String phone, List<PictureEntity> pictures, int pictureIndex, bool isLoadingPictures, bool isTakingPicture, bool isWaitingForPhoto, int photoCountdown, bool isCalling, RemoteConnectionErrorEvent? errorEvent, RemoteConnectionSuccessEvent? successEvent) $default,) {final _that = this;
switch (_that) {
case _RemoteConnectionViewState():
return $default(_that.deviceId,_that.dialCode,_that.phone,_that.pictures,_that.pictureIndex,_that.isLoadingPictures,_that.isTakingPicture,_that.isWaitingForPhoto,_that.photoCountdown,_that.isCalling,_that.errorEvent,_that.successEvent);case _:
return $default(_that.deviceId,_that.isoCode,_that.phone,_that.pictures,_that.pictureIndex,_that.isLoadingPictures,_that.isTakingPicture,_that.isWaitingForPhoto,_that.photoCountdown,_that.isCalling,_that.errorEvent,_that.successEvent);case _:
throw StateError('Unexpected subclass');
}
@@ -202,10 +202,10 @@ return $default(_that.deviceId,_that.dialCode,_that.phone,_that.pictures,_that.p
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String deviceId, String dialCode, String phone, List<PictureEntity> pictures, int pictureIndex, bool isLoadingPictures, bool isTakingPicture, bool isWaitingForPhoto, int photoCountdown, bool isCalling, RemoteConnectionErrorEvent? errorEvent, RemoteConnectionSuccessEvent? successEvent)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String deviceId, String isoCode, String phone, List<PictureEntity> pictures, int pictureIndex, bool isLoadingPictures, bool isTakingPicture, bool isWaitingForPhoto, int photoCountdown, bool isCalling, RemoteConnectionErrorEvent? errorEvent, RemoteConnectionSuccessEvent? successEvent)? $default,) {final _that = this;
switch (_that) {
case _RemoteConnectionViewState() when $default != null:
return $default(_that.deviceId,_that.dialCode,_that.phone,_that.pictures,_that.pictureIndex,_that.isLoadingPictures,_that.isTakingPicture,_that.isWaitingForPhoto,_that.photoCountdown,_that.isCalling,_that.errorEvent,_that.successEvent);case _:
return $default(_that.deviceId,_that.isoCode,_that.phone,_that.pictures,_that.pictureIndex,_that.isLoadingPictures,_that.isTakingPicture,_that.isWaitingForPhoto,_that.photoCountdown,_that.isCalling,_that.errorEvent,_that.successEvent);case _:
return null;
}
@@ -217,11 +217,11 @@ return $default(_that.deviceId,_that.dialCode,_that.phone,_that.pictures,_that.p
class _RemoteConnectionViewState implements RemoteConnectionViewState {
const _RemoteConnectionViewState({this.deviceId = '', this.dialCode = '+34', this.phone = '', final List<PictureEntity> pictures = const [], this.pictureIndex = 0, this.isLoadingPictures = true, this.isTakingPicture = false, this.isWaitingForPhoto = false, this.photoCountdown = 0, this.isCalling = false, this.errorEvent, this.successEvent}): _pictures = pictures;
const _RemoteConnectionViewState({this.deviceId = '', this.isoCode = 'ES', this.phone = '', final List<PictureEntity> pictures = const [], this.pictureIndex = 0, this.isLoadingPictures = true, this.isTakingPicture = false, this.isWaitingForPhoto = false, this.photoCountdown = 0, this.isCalling = false, this.errorEvent, this.successEvent}): _pictures = pictures;
@override@JsonKey() final String deviceId;
@override@JsonKey() final String dialCode;
@override@JsonKey() final String isoCode;
@override@JsonKey() final String phone;
final List<PictureEntity> _pictures;
@override@JsonKey() List<PictureEntity> get pictures {
@@ -249,16 +249,16 @@ _$RemoteConnectionViewStateCopyWith<_RemoteConnectionViewState> get copyWith =>
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _RemoteConnectionViewState&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.phone, phone) || other.phone == phone)&&const DeepCollectionEquality().equals(other._pictures, _pictures)&&(identical(other.pictureIndex, pictureIndex) || other.pictureIndex == pictureIndex)&&(identical(other.isLoadingPictures, isLoadingPictures) || other.isLoadingPictures == isLoadingPictures)&&(identical(other.isTakingPicture, isTakingPicture) || other.isTakingPicture == isTakingPicture)&&(identical(other.isWaitingForPhoto, isWaitingForPhoto) || other.isWaitingForPhoto == isWaitingForPhoto)&&(identical(other.photoCountdown, photoCountdown) || other.photoCountdown == photoCountdown)&&(identical(other.isCalling, isCalling) || other.isCalling == isCalling)&&(identical(other.errorEvent, errorEvent) || other.errorEvent == errorEvent)&&(identical(other.successEvent, successEvent) || other.successEvent == successEvent));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _RemoteConnectionViewState&&(identical(other.deviceId, deviceId) || other.deviceId == deviceId)&&(identical(other.isoCode, isoCode) || other.isoCode == isoCode)&&(identical(other.phone, phone) || other.phone == phone)&&const DeepCollectionEquality().equals(other._pictures, _pictures)&&(identical(other.pictureIndex, pictureIndex) || other.pictureIndex == pictureIndex)&&(identical(other.isLoadingPictures, isLoadingPictures) || other.isLoadingPictures == isLoadingPictures)&&(identical(other.isTakingPicture, isTakingPicture) || other.isTakingPicture == isTakingPicture)&&(identical(other.isWaitingForPhoto, isWaitingForPhoto) || other.isWaitingForPhoto == isWaitingForPhoto)&&(identical(other.photoCountdown, photoCountdown) || other.photoCountdown == photoCountdown)&&(identical(other.isCalling, isCalling) || other.isCalling == isCalling)&&(identical(other.errorEvent, errorEvent) || other.errorEvent == errorEvent)&&(identical(other.successEvent, successEvent) || other.successEvent == successEvent));
}
@override
int get hashCode => Object.hash(runtimeType,deviceId,dialCode,phone,const DeepCollectionEquality().hash(_pictures),pictureIndex,isLoadingPictures,isTakingPicture,isWaitingForPhoto,photoCountdown,isCalling,errorEvent,successEvent);
int get hashCode => Object.hash(runtimeType,deviceId,isoCode,phone,const DeepCollectionEquality().hash(_pictures),pictureIndex,isLoadingPictures,isTakingPicture,isWaitingForPhoto,photoCountdown,isCalling,errorEvent,successEvent);
@override
String toString() {
return 'RemoteConnectionViewState(deviceId: $deviceId, dialCode: $dialCode, phone: $phone, pictures: $pictures, pictureIndex: $pictureIndex, isLoadingPictures: $isLoadingPictures, isTakingPicture: $isTakingPicture, isWaitingForPhoto: $isWaitingForPhoto, photoCountdown: $photoCountdown, isCalling: $isCalling, errorEvent: $errorEvent, successEvent: $successEvent)';
return 'RemoteConnectionViewState(deviceId: $deviceId, isoCode: $isoCode, phone: $phone, pictures: $pictures, pictureIndex: $pictureIndex, isLoadingPictures: $isLoadingPictures, isTakingPicture: $isTakingPicture, isWaitingForPhoto: $isWaitingForPhoto, photoCountdown: $photoCountdown, isCalling: $isCalling, errorEvent: $errorEvent, successEvent: $successEvent)';
}
@@ -269,7 +269,7 @@ abstract mixin class _$RemoteConnectionViewStateCopyWith<$Res> implements $Remot
factory _$RemoteConnectionViewStateCopyWith(_RemoteConnectionViewState value, $Res Function(_RemoteConnectionViewState) _then) = __$RemoteConnectionViewStateCopyWithImpl;
@override @useResult
$Res call({
String deviceId, String dialCode, String phone, List<PictureEntity> pictures, int pictureIndex, bool isLoadingPictures, bool isTakingPicture, bool isWaitingForPhoto, int photoCountdown, bool isCalling, RemoteConnectionErrorEvent? errorEvent, RemoteConnectionSuccessEvent? successEvent
String deviceId, String isoCode, String phone, List<PictureEntity> pictures, int pictureIndex, bool isLoadingPictures, bool isTakingPicture, bool isWaitingForPhoto, int photoCountdown, bool isCalling, RemoteConnectionErrorEvent? errorEvent, RemoteConnectionSuccessEvent? successEvent
});
@@ -286,10 +286,10 @@ class __$RemoteConnectionViewStateCopyWithImpl<$Res>
/// Create a copy of RemoteConnectionViewState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? deviceId = null,Object? dialCode = null,Object? phone = null,Object? pictures = null,Object? pictureIndex = null,Object? isLoadingPictures = null,Object? isTakingPicture = null,Object? isWaitingForPhoto = null,Object? photoCountdown = null,Object? isCalling = null,Object? errorEvent = freezed,Object? successEvent = freezed,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? deviceId = null,Object? isoCode = null,Object? phone = null,Object? pictures = null,Object? pictureIndex = null,Object? isLoadingPictures = null,Object? isTakingPicture = null,Object? isWaitingForPhoto = null,Object? photoCountdown = null,Object? isCalling = null,Object? errorEvent = freezed,Object? successEvent = freezed,}) {
return _then(_RemoteConnectionViewState(
deviceId: null == deviceId ? _self.deviceId : deviceId // ignore: cast_nullable_to_non_nullable
as String,dialCode: null == dialCode ? _self.dialCode : dialCode // ignore: cast_nullable_to_non_nullable
as String,isoCode: null == isoCode ? _self.isoCode : isoCode // ignore: cast_nullable_to_non_nullable
as String,phone: null == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable
as String,pictures: null == pictures ? _self._pictures : pictures // ignore: cast_nullable_to_non_nullable
as List<PictureEntity>,pictureIndex: null == pictureIndex ? _self.pictureIndex : pictureIndex // ignore: cast_nullable_to_non_nullable

View File

@@ -67,6 +67,15 @@ class SpyCallDialog extends ConsumerWidget {
children: [
_Header(theme: theme),
SizedBox(height: SizeUtils.getByScreen(small: 8, big: 7)),
Text(
context.translate(I18n.spyCallSubtitle),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: SizeUtils.getByScreen(small: 13, big: 12),
color: Colors.black54,
),
),
SizedBox(height: SizeUtils.getByScreen(small: 12, big: 10)),
_PhoneSection(onSubmit: vm.call),
SizedBox(height: SizeUtils.getByScreen(small: 28, big: 27)),
_CallSection(onPressed: vm.call),
@@ -117,8 +126,8 @@ class _PhoneSection extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final vm = ref.read(remoteConnectionViewModelProvider.notifier);
final dialCode = ref.watch(
remoteConnectionViewModelProvider.select((s) => s.dialCode),
final isoCode = ref.watch(
remoteConnectionViewModelProvider.select((s) => s.isoCode),
);
return Row(
@@ -126,9 +135,10 @@ class _PhoneSection extends ConsumerWidget {
children: [
CountryPrefixPicker(
headerText: context.translate(I18n.selectYourCountry),
initialSelection: dialCode,
initialSelection: isoCode,
onChanged: (country) {
vm.updateDialCode(country.dialCode ?? dialCode);
final code = country.code;
if (code != null) vm.updateCountry(code);
},
width: 80,
),

View File

@@ -866,5 +866,7 @@
"appUpdateNow": "Jetzt aktualisieren",
"contactsPermissionBlocked": "Aktiviere die Kontakte-Berechtigung in den Systemeinstellungen, um zu importieren.",
"openSettings": "Einstellungen öffnen",
"errorMessageCodeIsEmpty": "Der Code darf nicht leer sein"
"errorMessageCodeIsEmpty": "Der Code darf nicht leer sein",
"callWatchSubtitle": "Gib die Telefonnummer des Geräts ein, das du anrufen möchtest.",
"spyCallSubtitle": "Das Gerät ruft diese Nummer an. Gib deine Telefonnummer ein, um den Anruf von der Uhr zu erhalten."
}

View File

@@ -866,5 +866,7 @@
"appUpdateNow": "Update now",
"contactsPermissionBlocked": "Enable the contacts permission in system settings to import.",
"openSettings": "Open settings",
"errorMessageCodeIsEmpty": "The code cannot be empty"
"errorMessageCodeIsEmpty": "The code cannot be empty",
"callWatchSubtitle": "Enter the phone number of the device you want to call.",
"spyCallSubtitle": "The device will call this number. Enter your phone to receive the call from the watch."
}

View File

@@ -866,5 +866,7 @@
"appUpdateNow": "Actualizar ahora",
"contactsPermissionBlocked": "Activa el permiso de contactos en los ajustes del sistema para importar.",
"openSettings": "Abrir ajustes",
"errorMessageCodeIsEmpty": "El código no puede estar vacío"
"errorMessageCodeIsEmpty": "El código no puede estar vacío",
"callWatchSubtitle": "Introduce el número de teléfono del dispositivo al que quieres llamar.",
"spyCallSubtitle": "El dispositivo llamará a este número. Introduce tu teléfono para recibir la llamada desde el reloj."
}

View File

@@ -866,5 +866,7 @@
"appUpdateNow": "Mettre à jour maintenant",
"contactsPermissionBlocked": "Active la permission des contacts dans les paramètres pour importer.",
"openSettings": "Ouvrir les paramètres",
"errorMessageCodeIsEmpty": "Le code ne peut pas être vide"
"errorMessageCodeIsEmpty": "Le code ne peut pas être vide",
"callWatchSubtitle": "Saisis le numéro de téléphone de l'appareil que tu veux appeler.",
"spyCallSubtitle": "L'appareil appellera ce numéro. Saisis ton téléphone pour recevoir l'appel de la montre."
}

View File

@@ -866,5 +866,7 @@
"appUpdateNow": "Aggiorna ora",
"contactsPermissionBlocked": "Attiva il permesso dei contatti nelle impostazioni per importare.",
"openSettings": "Apri impostazioni",
"errorMessageCodeIsEmpty": "Il codice non può essere vuoto"
"errorMessageCodeIsEmpty": "Il codice non può essere vuoto",
"callWatchSubtitle": "Inserisci il numero di telefono del dispositivo che vuoi chiamare.",
"spyCallSubtitle": "Il dispositivo chiamerà questo numero. Inserisci il tuo telefono per ricevere la chiamata dall'orologio."
}

View File

@@ -866,5 +866,7 @@
"appUpdateNow": "Atualizar agora",
"contactsPermissionBlocked": "Ativa a permissão de contactos nas definições para importar.",
"openSettings": "Abrir definições",
"errorMessageCodeIsEmpty": "O código não pode estar vazio"
"errorMessageCodeIsEmpty": "O código não pode estar vazio",
"callWatchSubtitle": "Digita o número de telefone do dispositivo que queres chamar.",
"spyCallSubtitle": "O dispositivo ligará para este número. Digita o teu telefone para receber a chamada do relógio."
}

View File

@@ -120,6 +120,8 @@ class I18n {
static const String callMissed = 'callMissed';
static const String callOutgoing = 'callOutgoing';
static const String callWatch = 'callWatch';
static const String callWatchSubtitle = 'callWatchSubtitle';
static const String spyCallSubtitle = 'spyCallSubtitle';
static const String cancel = 'cancel';
static const String cardPinChange = 'cardPinChange';
static const String cardPinChangeTitle = 'cardPinChangeTitle';