From c1c903ac935050d9060bdae94c70bc80e75f502e Mon Sep 17 00:00:00 2001 From: JulianAlcala Date: Wed, 25 Mar 2026 06:06:33 +0100 Subject: [PATCH] feat: add country code picker to call watch dialog --- modules/auth/devtools_options.yaml | 3 + modules/home/devtools_options.yaml | 3 + .../device_management_screen.dart | 46 +++++++------- .../state/call_watch_view_model.dart | 11 +++- .../state/call_watch_view_state.dart | 1 + .../state/call_watch_view_state.freezed.dart | 43 ++++++------- .../widgets/call_watch_dialog.dart | 60 ++++++++++++++----- .../presentation/settings_screen.dart | 44 +++++++------- 8 files changed, 128 insertions(+), 83 deletions(-) create mode 100644 modules/auth/devtools_options.yaml create mode 100644 modules/home/devtools_options.yaml diff --git a/modules/auth/devtools_options.yaml b/modules/auth/devtools_options.yaml new file mode 100644 index 00000000..fa0b357c --- /dev/null +++ b/modules/auth/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/modules/home/devtools_options.yaml b/modules/home/devtools_options.yaml new file mode 100644 index 00000000..fa0b357c --- /dev/null +++ b/modules/home/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/modules/legacy/modules/device_management/lib/src/features/device_management/device_management_screen.dart b/modules/legacy/modules/device_management/lib/src/features/device_management/device_management_screen.dart index 3f7b79ce..650b9ae8 100644 --- a/modules/legacy/modules/device_management/lib/src/features/device_management/device_management_screen.dart +++ b/modules/legacy/modules/device_management/lib/src/features/device_management/device_management_screen.dart @@ -51,14 +51,14 @@ class DeviceManagementScreen extends ConsumerWidget { negativeIcon: true, text: context.translate(I18n.contacts), ), - SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), - AppMenuButton( - color: theme.getColorFor(ThemeCode.legacyPrimary), - onPressed: () {}, - icon: SFIcons.doNotDisturbCircle, - negativeIcon: true, - text: context.translate(I18n.doNotDisturb), - ), + // SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), + // AppMenuButton( + // color: theme.getColorFor(ThemeCode.legacyPrimary), + // onPressed: () {}, + // icon: SFIcons.doNotDisturbCircle, + // negativeIcon: true, + // text: context.translate(I18n.doNotDisturb), + // ), // SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), // AppMenuButton( // color: theme.getColorFor(ThemeCode.legacyPrimary), @@ -128,21 +128,21 @@ class DeviceManagementScreen extends ConsumerWidget { icon: SFIcons.screenTime, text: context.translate(I18n.appsUse), ), - SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), - AppMenuButton( - color: theme.getColorFor(ThemeCode.legacyPrimary), - onPressed: () {}, - icon: Icons.app_registration_sharp, - text: context.translate(I18n.appsSurveillance), - ), - SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), - AppMenuButton( - color: theme.getColorFor(ThemeCode.legacyPrimary), - onPressed: () {}, - icon: SFIcons.friendsCircle, - negativeIcon: true, - text: context.translate(I18n.makeFriends), - ), + // SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), + // AppMenuButton( + // color: theme.getColorFor(ThemeCode.legacyPrimary), + // onPressed: () {}, + // icon: Icons.app_registration_sharp, + // text: context.translate(I18n.appsSurveillance), + // ), + // SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), + // AppMenuButton( + // color: theme.getColorFor(ThemeCode.legacyPrimary), + // onPressed: () {}, + // icon: SFIcons.friendsCircle, + // negativeIcon: true, + // text: context.translate(I18n.makeFriends), + // ), SizedBox(height: SizeUtils.getByScreen(small: 16, big: 15)), AppMenuButton( color: theme.getColorFor(ThemeCode.legacyPrimary), diff --git a/modules/legacy/modules/device_management/lib/src/features/device_management/state/call_watch_view_model.dart b/modules/legacy/modules/device_management/lib/src/features/device_management/state/call_watch_view_model.dart index 608f2a08..46d9e19b 100644 --- a/modules/legacy/modules/device_management/lib/src/features/device_management/state/call_watch_view_model.dart +++ b/modules/legacy/modules/device_management/lib/src/features/device_management/state/call_watch_view_model.dart @@ -32,10 +32,14 @@ class CallWatchViewModel extends Notifier { state = state.copyWith(phone: text, errorMessage: ''); } - + + void updateDialCode(String code) { + state = state.copyWith(dialCode: code, errorMessage: ''); + } + void call() async { final phone = state.phone; - if (phone.isEmpty){ + if (phone.isEmpty) { state = state.copyWith(errorMessage: 'errorMessagePhoneIsEmpty'); return; } @@ -44,7 +48,8 @@ class CallWatchViewModel extends Notifier { return; } - final url = Uri(scheme: 'tel', path: phone); + final fullNumber = '${state.dialCode}$phone'; + final url = Uri(scheme: 'tel', path: fullNumber); if (await canLaunchUrl(url)) { launchUrl(url); diff --git a/modules/legacy/modules/device_management/lib/src/features/device_management/state/call_watch_view_state.dart b/modules/legacy/modules/device_management/lib/src/features/device_management/state/call_watch_view_state.dart index 1b6d38b4..aebe3db4 100644 --- a/modules/legacy/modules/device_management/lib/src/features/device_management/state/call_watch_view_state.dart +++ b/modules/legacy/modules/device_management/lib/src/features/device_management/state/call_watch_view_state.dart @@ -5,6 +5,7 @@ part 'call_watch_view_state.freezed.dart'; @freezed abstract class CallWatchViewState with _$CallWatchViewState { const factory CallWatchViewState({ + @Default('+34') String dialCode, @Default('') String phone, @Default('') String errorMessage, }) = _CallWatchViewState; diff --git a/modules/legacy/modules/device_management/lib/src/features/device_management/state/call_watch_view_state.freezed.dart b/modules/legacy/modules/device_management/lib/src/features/device_management/state/call_watch_view_state.freezed.dart index 09f3d35a..f5ba6a9a 100644 --- a/modules/legacy/modules/device_management/lib/src/features/device_management/state/call_watch_view_state.freezed.dart +++ b/modules/legacy/modules/device_management/lib/src/features/device_management/state/call_watch_view_state.freezed.dart @@ -14,7 +14,7 @@ T _$identity(T value) => value; /// @nodoc mixin _$CallWatchViewState { - String get phone; String get errorMessage; + String get dialCode; 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 get copyWith => _$CallWatchViewS @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is CallWatchViewState&&(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.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.phone, phone) || other.phone == phone)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)); } @override -int get hashCode => Object.hash(runtimeType,phone,errorMessage); +int get hashCode => Object.hash(runtimeType,dialCode,phone,errorMessage); @override String toString() { - return 'CallWatchViewState(phone: $phone, errorMessage: $errorMessage)'; + return 'CallWatchViewState(dialCode: $dialCode, 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 phone, String errorMessage + String dialCode, String phone, String errorMessage }); @@ -62,9 +62,10 @@ 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? phone = null,Object? errorMessage = null,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? dialCode = null,Object? phone = null,Object? errorMessage = null,}) { return _then(_self.copyWith( -phone: null == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable +dialCode: null == dialCode ? _self.dialCode : dialCode // 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, )); @@ -151,10 +152,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( String phone, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( String dialCode, String phone, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _CallWatchViewState() when $default != null: -return $default(_that.phone,_that.errorMessage);case _: +return $default(_that.dialCode,_that.phone,_that.errorMessage);case _: return orElse(); } @@ -172,10 +173,10 @@ return $default(_that.phone,_that.errorMessage);case _: /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( String phone, String errorMessage) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( String dialCode, String phone, String errorMessage) $default,) {final _that = this; switch (_that) { case _CallWatchViewState(): -return $default(_that.phone,_that.errorMessage);case _: +return $default(_that.dialCode,_that.phone,_that.errorMessage);case _: throw StateError('Unexpected subclass'); } @@ -192,10 +193,10 @@ return $default(_that.phone,_that.errorMessage);case _: /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( String phone, String errorMessage)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( String dialCode, String phone, String errorMessage)? $default,) {final _that = this; switch (_that) { case _CallWatchViewState() when $default != null: -return $default(_that.phone,_that.errorMessage);case _: +return $default(_that.dialCode,_that.phone,_that.errorMessage);case _: return null; } @@ -207,9 +208,10 @@ return $default(_that.phone,_that.errorMessage);case _: class _CallWatchViewState implements CallWatchViewState { - const _CallWatchViewState({this.phone = '', this.errorMessage = ''}); + const _CallWatchViewState({this.dialCode = '+34', this.phone = '', this.errorMessage = ''}); +@override@JsonKey() final String dialCode; @override@JsonKey() final String phone; @override@JsonKey() final String errorMessage; @@ -223,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.phone, phone) || other.phone == phone)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)); + 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)); } @override -int get hashCode => Object.hash(runtimeType,phone,errorMessage); +int get hashCode => Object.hash(runtimeType,dialCode,phone,errorMessage); @override String toString() { - return 'CallWatchViewState(phone: $phone, errorMessage: $errorMessage)'; + return 'CallWatchViewState(dialCode: $dialCode, phone: $phone, errorMessage: $errorMessage)'; } @@ -243,7 +245,7 @@ abstract mixin class _$CallWatchViewStateCopyWith<$Res> implements $CallWatchVie factory _$CallWatchViewStateCopyWith(_CallWatchViewState value, $Res Function(_CallWatchViewState) _then) = __$CallWatchViewStateCopyWithImpl; @override @useResult $Res call({ - String phone, String errorMessage + String dialCode, String phone, String errorMessage }); @@ -260,9 +262,10 @@ 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? phone = null,Object? errorMessage = null,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? dialCode = null,Object? phone = null,Object? errorMessage = null,}) { return _then(_CallWatchViewState( -phone: null == phone ? _self.phone : phone // ignore: cast_nullable_to_non_nullable +dialCode: null == dialCode ? _self.dialCode : dialCode // 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, )); diff --git a/modules/legacy/modules/device_management/lib/src/features/device_management/widgets/call_watch_dialog.dart b/modules/legacy/modules/device_management/lib/src/features/device_management/widgets/call_watch_dialog.dart index c2be5559..b07b703e 100644 --- a/modules/legacy/modules/device_management/lib/src/features/device_management/widgets/call_watch_dialog.dart +++ b/modules/legacy/modules/device_management/lib/src/features/device_management/widgets/call_watch_dialog.dart @@ -6,6 +6,7 @@ import 'package:sf_localizations/sf_localizations.dart'; import 'package:utils/utils.dart'; class CallWatchDialog extends ConsumerWidget { + const CallWatchDialog({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -17,7 +18,7 @@ class CallWatchDialog extends ConsumerWidget { return Container( padding: SizeUtils.getByScreen( small: EdgeInsets.symmetric(horizontal: 26, vertical: 20), - big: EdgeInsets.symmetric(horizontal: 24, vertical: 18) + big: EdgeInsets.symmetric(horizontal: 24, vertical: 18), ), width: SizeUtils.getByScreen(small: 390, big: 380), height: SizeUtils.getByScreen(small: 250, big: 243), @@ -25,24 +26,54 @@ class CallWatchDialog extends ConsumerWidget { children: [ Stack( children: [ - Center(child: Text(context.translate(I18n.callWatch), - textAlign: TextAlign.center, - style: TextStyle(fontSize: SizeUtils.getByScreen(small: 19, big: 18)), - )), + Center( + child: Text( + context.translate(I18n.callWatch), + textAlign: TextAlign.center, + style: TextStyle( + fontSize: SizeUtils.getByScreen(small: 19, big: 18), + ), + ), + ), Align( alignment: Alignment.centerRight, child: IconButton( - onPressed: (){Navigator.pop(context);}, - icon: Icon(Icons.close, color: theme.getColorFor(ThemeCode.legacyPrimary)), - ) - ) + onPressed: () { + Navigator.pop(context); + }, + icon: Icon( + Icons.close, + color: theme.getColorFor(ThemeCode.legacyPrimary), + ), + ), + ), ], ), SizedBox(height: SizeUtils.getByScreen(small: 8, big: 7)), - CustomTextField( - controller: viewModel.phoneController, - hint: context.translate(I18n.mainContactPhoneNumber), - keyboardType: TextInputType.number, + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + CountryPrefixPicker( + headerText: context.translate(I18n.selectYourCountry), + initialSelection: viewState.dialCode, + onChanged: (country) { + viewModel.updateDialCode( + country.dialCode ?? viewState.dialCode, + ); + }, + width: 80, + backgroundColor: Colors.transparent, + borderColor: Colors.black, + ), + SizedBox(width: SizeUtils.getByScreen(small: 8, big: 7)), + Expanded( + child: CustomTextField( + controller: viewModel.phoneController, + hint: context.translate(I18n.mainContactPhoneNumber), + keyboardType: TextInputType.phone, + ), + ), + ], ), if (viewState.errorMessage.isNotEmpty) Padding( @@ -68,5 +99,4 @@ class CallWatchDialog extends ConsumerWidget { ), ); } - -} \ No newline at end of file +} diff --git a/modules/legacy/modules/settings/lib/src/features/settings/presentation/settings_screen.dart b/modules/legacy/modules/settings/lib/src/features/settings/presentation/settings_screen.dart index 48a2f66e..6965b4a0 100644 --- a/modules/legacy/modules/settings/lib/src/features/settings/presentation/settings_screen.dart +++ b/modules/legacy/modules/settings/lib/src/features/settings/presentation/settings_screen.dart @@ -34,13 +34,13 @@ class SettingsScreen extends ConsumerWidget { text: I18n.alarm, color: color, ), - _item( - context, - onPressed: () => navigationContract.pushTo(AppRoutes.appStore), - icon: Icons.apps_rounded, - text: I18n.appStore, - color: color, - ), + // _item( + // context, + // onPressed: () => navigationContract.pushTo(AppRoutes.appStore), + // icon: Icons.apps_rounded, + // text: I18n.appStore, + // color: color, + // ), _item( context, onPressed: () => @@ -109,14 +109,14 @@ class SettingsScreen extends ConsumerWidget { // text: I18n.wifiSettings, // color: color, // ), - _item( - context, - onPressed: () => - navigationContract.pushTo(AppRoutes.remoteOnOff), - icon: Icons.settings_power_outlined, - text: I18n.remoteOnOff, - color: color, - ), + // _item( + // context, + // onPressed: () => + // navigationContract.pushTo(AppRoutes.remoteOnOff), + // icon: Icons.settings_power_outlined, + // text: I18n.remoteOnOff, + // color: color, + // ), _item( context, onPressed: () => @@ -125,13 +125,13 @@ class SettingsScreen extends ConsumerWidget { text: I18n.disableFunctions, color: color, ), - _item( - context, - onPressed: () => navigationContract.pushTo(AppRoutes.syncClock), - icon: Icons.share_arrival_time_outlined, - text: I18n.syncClock, - color: color, - ), + // _item( + // context, + // onPressed: () => navigationContract.pushTo(AppRoutes.syncClock), + // icon: Icons.share_arrival_time_outlined, + // text: I18n.syncClock, + // color: color, + // ), ], ), ),