feat: add country code picker to call watch dialog

This commit is contained in:
2026-03-25 06:06:33 +01:00
parent a0a782c91b
commit c1c903ac93
8 changed files with 128 additions and 83 deletions

View File

@@ -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),

View File

@@ -32,10 +32,14 @@ class CallWatchViewModel extends Notifier<CallWatchViewState> {
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<CallWatchViewState> {
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);

View File

@@ -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;

View File

@@ -14,7 +14,7 @@ T _$identity<T>(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<CallWatchViewState> 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 extends Object?>(TResult Function( String phone, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this;
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(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 extends Object?>(TResult Function( String phone, String errorMessage) $default,) {final _that = this;
@optionalTypeArgs TResult when<TResult extends Object?>(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 extends Object?>(TResult? Function( String phone, String errorMessage)? $default,) {final _that = this;
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(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,
));

View File

@@ -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 {
),
);
}
}
}

View File

@@ -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,
// ),
],
),
),