diff --git a/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/edit_contact_screen.dart b/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/edit_contact_screen.dart index d16f05b6..e0aa2558 100644 --- a/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/edit_contact_screen.dart +++ b/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/edit_contact_screen.dart @@ -46,6 +46,8 @@ class _EditContactScreenState extends ConsumerState { Widget build(BuildContext context) { final theme = ref.watch(themePortProvider); + final state = ref.watch(contactsViewModelProvider); + return Scaffold( backgroundColor: theme.getColorFor(ThemeCode.backgroundPrimary), body: SafeArea( @@ -101,10 +103,31 @@ class _EditContactScreenState extends ConsumerState { SizedBox( height: SizeUtils.getByScreen(small: 28, big: 26), ), - CustomTextField( - controller: _phoneController, - keyboardType: TextInputType.number, - label: context.translate(I18n.phoneNumber), + Row( + children: [ + CountryPrefixPicker( + headerText: context.translate(I18n.selectYourCountry), + initialSelection: state.dialCode, + onChanged: (country) { + final vm = + ref.read(contactsViewModelProvider.notifier); + vm.updateDialCode( + country.dialCode ?? state.dialCode, + ); + }, + width: 80, + ), + SizedBox( + width: SizeUtils.getByScreen(small: 10, big: 10, xl: 6), + ), + Expanded( + child: CustomTextField( + controller: _phoneController, + keyboardType: TextInputType.number, + label: context.translate(I18n.phoneNumber), + ), + ), + ], ), ], ), diff --git a/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/state/contacts_view_model.dart b/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/state/contacts_view_model.dart index fceb2eb8..32ad2a65 100644 --- a/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/state/contacts_view_model.dart +++ b/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/state/contacts_view_model.dart @@ -48,6 +48,15 @@ class ContactsViewModel extends Notifier { state = state.copyWith(isEditing: !state.isEditing); } + void updateDialCode(String value) { + if (value == state.dialCode) return; + + state = state.copyWith( + dialCode: value, + errorMessage: '', + ); + } + Future createContact({ required String name, required String phone, @@ -64,13 +73,16 @@ class ContactsViewModel extends Notifier { try { state = state.copyWith(isLoading: true, errorMessage: ''); + final dialCode = state.dialCode; + final fullPhone = dialCode+phone; + final user = await ref.read(userInfoProvider.future); if (!ref.mounted) return false; final request = CreateContactRequestModel( id: _uuid.v4(), name: name, - phone: phone, + phone: fullPhone, userId: user.id, ); @@ -98,10 +110,13 @@ class ContactsViewModel extends Notifier { try { state = state.copyWith(isLoading: true, errorMessage: ''); + final dialCode = state.dialCode; + final fullPhone = phone.isEmpty ? contact.phone : dialCode + phone; + final request = UpdateContactRequestModel( id: contact.id, name: name.isEmpty ? contact.name : name, - phone: phone.isEmpty ? contact.phone : phone, + phone: fullPhone, ); await _contactsRepository.updateContact(request: request); diff --git a/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/state/contacts_view_state.dart b/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/state/contacts_view_state.dart index 5411421a..c3e99a9b 100644 --- a/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/state/contacts_view_state.dart +++ b/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/state/contacts_view_state.dart @@ -8,6 +8,7 @@ part 'contacts_view_state.freezed.dart'; abstract class ContactsViewState with _$ContactsViewState { const factory ContactsViewState({ @Default([]) List contacts, + @Default('+34') String dialCode, @Default(true) bool isLoading, @Default(false) bool isEditing, @Default('') String errorMessage, diff --git a/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/state/contacts_view_state.freezed.dart b/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/state/contacts_view_state.freezed.dart index 5b1b4395..d97a78bd 100644 --- a/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/state/contacts_view_state.freezed.dart +++ b/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/state/contacts_view_state.freezed.dart @@ -14,7 +14,7 @@ T _$identity(T value) => value; /// @nodoc mixin _$ContactsViewState { - List get contacts; bool get isLoading; bool get isEditing; String get errorMessage; + List get contacts; String get dialCode; bool get isLoading; bool get isEditing; String get errorMessage; /// Create a copy of ContactsViewState /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -25,16 +25,16 @@ $ContactsViewStateCopyWith get copyWith => _$ContactsViewStat @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is ContactsViewState&&const DeepCollectionEquality().equals(other.contacts, contacts)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isEditing, isEditing) || other.isEditing == isEditing)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is ContactsViewState&&const DeepCollectionEquality().equals(other.contacts, contacts)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isEditing, isEditing) || other.isEditing == isEditing)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)); } @override -int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(contacts),isLoading,isEditing,errorMessage); +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(contacts),dialCode,isLoading,isEditing,errorMessage); @override String toString() { - return 'ContactsViewState(contacts: $contacts, isLoading: $isLoading, isEditing: $isEditing, errorMessage: $errorMessage)'; + return 'ContactsViewState(contacts: $contacts, dialCode: $dialCode, isLoading: $isLoading, isEditing: $isEditing, errorMessage: $errorMessage)'; } @@ -45,7 +45,7 @@ abstract mixin class $ContactsViewStateCopyWith<$Res> { factory $ContactsViewStateCopyWith(ContactsViewState value, $Res Function(ContactsViewState) _then) = _$ContactsViewStateCopyWithImpl; @useResult $Res call({ - List contacts, bool isLoading, bool isEditing, String errorMessage + List contacts, String dialCode, bool isLoading, bool isEditing, String errorMessage }); @@ -62,10 +62,11 @@ class _$ContactsViewStateCopyWithImpl<$Res> /// Create a copy of ContactsViewState /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? contacts = null,Object? isLoading = null,Object? isEditing = null,Object? errorMessage = null,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? contacts = null,Object? dialCode = null,Object? isLoading = null,Object? isEditing = null,Object? errorMessage = null,}) { return _then(_self.copyWith( contacts: null == contacts ? _self.contacts : contacts // ignore: cast_nullable_to_non_nullable -as List,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable +as List,dialCode: null == dialCode ? _self.dialCode : dialCode // ignore: cast_nullable_to_non_nullable +as String,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable as bool,isEditing: null == isEditing ? _self.isEditing : isEditing // ignore: cast_nullable_to_non_nullable as bool,errorMessage: null == errorMessage ? _self.errorMessage : errorMessage // ignore: cast_nullable_to_non_nullable as String, @@ -153,10 +154,10 @@ return $default(_that);case _: /// } /// ``` -@optionalTypeArgs TResult maybeWhen(TResult Function( List contacts, bool isLoading, bool isEditing, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this; +@optionalTypeArgs TResult maybeWhen(TResult Function( List contacts, String dialCode, bool isLoading, bool isEditing, String errorMessage)? $default,{required TResult orElse(),}) {final _that = this; switch (_that) { case _ContactsViewState() when $default != null: -return $default(_that.contacts,_that.isLoading,_that.isEditing,_that.errorMessage);case _: +return $default(_that.contacts,_that.dialCode,_that.isLoading,_that.isEditing,_that.errorMessage);case _: return orElse(); } @@ -174,10 +175,10 @@ return $default(_that.contacts,_that.isLoading,_that.isEditing,_that.errorMessag /// } /// ``` -@optionalTypeArgs TResult when(TResult Function( List contacts, bool isLoading, bool isEditing, String errorMessage) $default,) {final _that = this; +@optionalTypeArgs TResult when(TResult Function( List contacts, String dialCode, bool isLoading, bool isEditing, String errorMessage) $default,) {final _that = this; switch (_that) { case _ContactsViewState(): -return $default(_that.contacts,_that.isLoading,_that.isEditing,_that.errorMessage);case _: +return $default(_that.contacts,_that.dialCode,_that.isLoading,_that.isEditing,_that.errorMessage);case _: throw StateError('Unexpected subclass'); } @@ -194,10 +195,10 @@ return $default(_that.contacts,_that.isLoading,_that.isEditing,_that.errorMessag /// } /// ``` -@optionalTypeArgs TResult? whenOrNull(TResult? Function( List contacts, bool isLoading, bool isEditing, String errorMessage)? $default,) {final _that = this; +@optionalTypeArgs TResult? whenOrNull(TResult? Function( List contacts, String dialCode, bool isLoading, bool isEditing, String errorMessage)? $default,) {final _that = this; switch (_that) { case _ContactsViewState() when $default != null: -return $default(_that.contacts,_that.isLoading,_that.isEditing,_that.errorMessage);case _: +return $default(_that.contacts,_that.dialCode,_that.isLoading,_that.isEditing,_that.errorMessage);case _: return null; } @@ -209,7 +210,7 @@ return $default(_that.contacts,_that.isLoading,_that.isEditing,_that.errorMessag class _ContactsViewState implements ContactsViewState { - const _ContactsViewState({final List contacts = const [], this.isLoading = true, this.isEditing = false, this.errorMessage = ''}): _contacts = contacts; + const _ContactsViewState({final List contacts = const [], this.dialCode = '+34', this.isLoading = true, this.isEditing = false, this.errorMessage = ''}): _contacts = contacts; final List _contacts; @@ -219,6 +220,7 @@ class _ContactsViewState implements ContactsViewState { return EqualUnmodifiableListView(_contacts); } +@override@JsonKey() final String dialCode; @override@JsonKey() final bool isLoading; @override@JsonKey() final bool isEditing; @override@JsonKey() final String errorMessage; @@ -233,16 +235,16 @@ _$ContactsViewStateCopyWith<_ContactsViewState> get copyWith => __$ContactsViewS @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _ContactsViewState&&const DeepCollectionEquality().equals(other._contacts, _contacts)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isEditing, isEditing) || other.isEditing == isEditing)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _ContactsViewState&&const DeepCollectionEquality().equals(other._contacts, _contacts)&&(identical(other.dialCode, dialCode) || other.dialCode == dialCode)&&(identical(other.isLoading, isLoading) || other.isLoading == isLoading)&&(identical(other.isEditing, isEditing) || other.isEditing == isEditing)&&(identical(other.errorMessage, errorMessage) || other.errorMessage == errorMessage)); } @override -int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_contacts),isLoading,isEditing,errorMessage); +int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_contacts),dialCode,isLoading,isEditing,errorMessage); @override String toString() { - return 'ContactsViewState(contacts: $contacts, isLoading: $isLoading, isEditing: $isEditing, errorMessage: $errorMessage)'; + return 'ContactsViewState(contacts: $contacts, dialCode: $dialCode, isLoading: $isLoading, isEditing: $isEditing, errorMessage: $errorMessage)'; } @@ -253,7 +255,7 @@ abstract mixin class _$ContactsViewStateCopyWith<$Res> implements $ContactsViewS factory _$ContactsViewStateCopyWith(_ContactsViewState value, $Res Function(_ContactsViewState) _then) = __$ContactsViewStateCopyWithImpl; @override @useResult $Res call({ - List contacts, bool isLoading, bool isEditing, String errorMessage + List contacts, String dialCode, bool isLoading, bool isEditing, String errorMessage }); @@ -270,10 +272,11 @@ class __$ContactsViewStateCopyWithImpl<$Res> /// Create a copy of ContactsViewState /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? contacts = null,Object? isLoading = null,Object? isEditing = null,Object? errorMessage = null,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? contacts = null,Object? dialCode = null,Object? isLoading = null,Object? isEditing = null,Object? errorMessage = null,}) { return _then(_ContactsViewState( contacts: null == contacts ? _self._contacts : contacts // ignore: cast_nullable_to_non_nullable -as List,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable +as List,dialCode: null == dialCode ? _self.dialCode : dialCode // ignore: cast_nullable_to_non_nullable +as String,isLoading: null == isLoading ? _self.isLoading : isLoading // ignore: cast_nullable_to_non_nullable as bool,isEditing: null == isEditing ? _self.isEditing : isEditing // ignore: cast_nullable_to_non_nullable as bool,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/contacts/presentation/widgets/contact_card.dart b/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/widgets/contact_card.dart index ccc828e3..306a7b7c 100644 --- a/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/widgets/contact_card.dart +++ b/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/widgets/contact_card.dart @@ -25,7 +25,7 @@ class ContactCard extends ConsumerWidget { return Container( padding: EdgeInsets.symmetric( horizontal: SizeUtils.getByScreen(small: 22, big: 21), - vertical: SizeUtils.getByScreen(small: 10, big: 8), + vertical: SizeUtils.getByScreen(small: 12, big: 8), ), decoration: BoxDecoration( borderRadius: BorderRadius.all( @@ -41,7 +41,7 @@ class ContactCard extends ConsumerWidget { color: theme.getColorFor(ThemeCode.backgroundPrimary), ), padding: - EdgeInsets.all(SizeUtils.getByScreen(small: 4, big: 12)), + EdgeInsets.all(SizeUtils.getByScreen(small: 10, big: 12)), child: Icon( SFIcons.account, size: SizeUtils.getByScreen(small: 40, big: 44), diff --git a/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/widgets/new_contact_dialog.dart b/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/widgets/new_contact_dialog.dart index e907266b..d3b01bc1 100644 --- a/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/widgets/new_contact_dialog.dart +++ b/modules/legacy/modules/device_management/lib/src/features/contacts/presentation/widgets/new_contact_dialog.dart @@ -29,6 +29,10 @@ class _NewContactDialogState extends ConsumerState { @override Widget build(BuildContext context) { final theme = ref.watch(themePortProvider); + + final dialCode = ref.read( + contactsViewModelProvider.select((s)=>s.dialCode) + ); return Container( padding: EdgeInsets.symmetric( @@ -82,12 +86,23 @@ class _NewContactDialogState extends ConsumerState { Row( spacing: SizeUtils.getByScreen(small: 10, big: 8), children: [ + + CountryPrefixPicker( + headerText: context.translate(I18n.selectYourCountry), + initialSelection: dialCode, + onChanged: (country) { + final vm = ref.read(contactsViewModelProvider.notifier); + vm.updateDialCode( + country.dialCode ?? dialCode, + ); + }, + width: 80, + ), Expanded( child: CustomTextField( controller: _phoneController, hint: context.translate(I18n.phoneNumber), keyboardType: TextInputType.phone, - readOnly: true, ), ), DecoratedBox(