diff --git a/modules/legacy/modules/settings/lib/src/core/presentation/widgets/contact_list_contact_card.dart b/modules/legacy/modules/settings/lib/src/core/presentation/widgets/contact_list_contact_card.dart index 635ae470..37607b3c 100644 --- a/modules/legacy/modules/settings/lib/src/core/presentation/widgets/contact_list_contact_card.dart +++ b/modules/legacy/modules/settings/lib/src/core/presentation/widgets/contact_list_contact_card.dart @@ -6,11 +6,13 @@ import '../../domain/entities/contact_list_contact_entity.dart'; class ContactListContactCard extends StatelessWidget { final ContactListContactEntity contact; + final VoidCallback? onEdit; final VoidCallback onDelete; const ContactListContactCard({ super.key, required this.contact, + this.onEdit, required this.onDelete, }); @@ -61,6 +63,21 @@ class ContactListContactCard extends StatelessWidget { ], ), ), + if (onEdit != null) + InkWell( + onTap: onEdit, + borderRadius: BorderRadius.circular(8), + child: Padding( + padding: EdgeInsets.all( + SizeUtils.getByScreen(small: 6, big: 8), + ), + child: Icon( + Icons.edit_outlined, + color: context.sfColors.legacyPrimary, + size: SizeUtils.getByScreen(small: 22, big: 24), + ), + ), + ), InkWell( onTap: onDelete, borderRadius: BorderRadius.circular(8), diff --git a/modules/legacy/modules/settings/lib/src/features/block_phone/presentation/block_phone_screen.dart b/modules/legacy/modules/settings/lib/src/features/block_phone/presentation/block_phone_screen.dart index 87ab8e7e..ee34f3e5 100644 --- a/modules/legacy/modules/settings/lib/src/features/block_phone/presentation/block_phone_screen.dart +++ b/modules/legacy/modules/settings/lib/src/features/block_phone/presentation/block_phone_screen.dart @@ -192,6 +192,11 @@ class _ContactList extends ConsumerWidget { final contact = contacts[index]; return ContactListContactCard( contact: contact, + onEdit: () => showEditContactSheet( + context, + index: index, + contact: contact, + ), onDelete: () => _confirmDelete(context, ref, index, contact.name), ); diff --git a/modules/legacy/modules/settings/lib/src/features/block_phone/presentation/state/block_phone_view_model.dart b/modules/legacy/modules/settings/lib/src/features/block_phone/presentation/state/block_phone_view_model.dart index 331012d1..3b42e79a 100644 --- a/modules/legacy/modules/settings/lib/src/features/block_phone/presentation/state/block_phone_view_model.dart +++ b/modules/legacy/modules/settings/lib/src/features/block_phone/presentation/state/block_phone_view_model.dart @@ -80,6 +80,37 @@ class BlockPhoneViewModel extends Notifier { } } + Future updateContact(int index, ContactListContactEntity contact) async { + state = state.copyWith(isSaving: true, errorMessage: ''); + + try { + final device = ref.read(selectedDeviceProvider).value; + if (device == null) return; + + final updatedContacts = [...state.contacts]; + updatedContacts[index] = contact; + + await _repository.upsertWhitelist( + userId: device.userId ?? '', + deviceId: device.id, + contacts: updatedContacts, + ); + if (!ref.mounted) return; + + state = state.copyWith( + contacts: updatedContacts, + isSaving: false, + successMessage: I18n.numberUpdated, + ); + } catch (e) { + if (!ref.mounted) return; + state = state.copyWith( + isSaving: false, + errorMessage: formatErrorMessage(e), + ); + } + } + Future removeContact(int index) async { state = state.copyWith(isSaving: true, errorMessage: ''); diff --git a/modules/legacy/modules/settings/lib/src/features/block_phone/presentation/widgets/add_contact_sheet.dart b/modules/legacy/modules/settings/lib/src/features/block_phone/presentation/widgets/add_contact_sheet.dart index 1419ed55..11234ada 100644 --- a/modules/legacy/modules/settings/lib/src/features/block_phone/presentation/widgets/add_contact_sheet.dart +++ b/modules/legacy/modules/settings/lib/src/features/block_phone/presentation/widgets/add_contact_sheet.dart @@ -3,8 +3,11 @@ import 'package:legacy_theme/legacy_theme.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:sf_localizations/sf_localizations.dart'; +import 'package:sf_shared/sf_shared.dart'; +import 'package:settings/src/core/domain/entities/contact_list_contact_entity.dart'; import 'package:settings/src/core/presentation/widgets/contact_form_sheet.dart'; +import 'package:settings/src/features/block_phone/presentation/state/block_phone_view_model.dart'; import 'package:settings/src/features/block_phone/presentation/state/new_block_phone_contact_view_model.dart'; void showAddContactSheet(BuildContext context) { @@ -16,6 +19,19 @@ void showAddContactSheet(BuildContext context) { ); } +void showEditContactSheet( + BuildContext context, { + required int index, + required ContactListContactEntity contact, +}) { + showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: Colors.transparent, + builder: (_) => _EditContactSheet(index: index, contact: contact), + ); +} + class _AddContactSheet extends ConsumerWidget { const _AddContactSheet(); @@ -55,3 +71,98 @@ class _AddContactSheet extends ConsumerWidget { ); } } + +class _EditContactSheet extends ConsumerStatefulWidget { + final int index; + final ContactListContactEntity contact; + + const _EditContactSheet({required this.index, required this.contact}); + + @override + ConsumerState<_EditContactSheet> createState() => _EditContactSheetState(); +} + +class _EditContactSheetState extends ConsumerState<_EditContactSheet> { + late final TextEditingController _nameController; + late final TextEditingController _phoneController; + String _isoCode = SfPhoneNumber.defaultIsoCode; + bool _canSave = true; + bool _isSubmitting = false; + String? _phoneError; + + @override + void initState() { + super.initState(); + _nameController = TextEditingController(text: widget.contact.name); + + final parsed = SfPhoneNumber.tryParse(widget.contact.phone); + _phoneController = TextEditingController( + text: parsed?.nationalNumber ?? widget.contact.phone, + ); + if (parsed != null) _isoCode = parsed.isoCode; + + _nameController.addListener(_refreshCanSave); + _phoneController.addListener(_refreshCanSave); + } + + @override + void dispose() { + _nameController.dispose(); + _phoneController.dispose(); + super.dispose(); + } + + void _refreshCanSave() { + final canSave = + _nameController.text.trim().isNotEmpty && + _phoneController.text.trim().isNotEmpty; + if (canSave != _canSave) setState(() => _canSave = canSave); + if (_phoneError != null) setState(() => _phoneError = null); + } + + Future _submit() async { + if (_isSubmitting || !_canSave) return; + + final parsed = SfPhoneNumber.tryParse( + _phoneController.text, + defaultIsoCode: _isoCode, + ); + if (parsed == null) { + setState(() => _phoneError = I18n.errorMessagePhoneIsInvalid); + return; + } + + setState(() => _isSubmitting = true); + + await ref + .read(blockPhoneViewModelProvider.notifier) + .updateContact( + widget.index, + ContactListContactEntity( + name: _nameController.text.trim(), + phone: parsed.e164, + ), + ); + + if (!mounted) return; + setState(() => _isSubmitting = false); + Navigator.pop(context); + } + + @override + Widget build(BuildContext context) { + return ContactFormSheet( + title: context.translate(I18n.editAllowedNumber), + primaryColor: context.sfColors.legacyPrimary, + nameController: _nameController, + phoneController: _phoneController, + isoCode: _isoCode, + canSave: _canSave, + isSubmitting: _isSubmitting, + phoneError: _phoneError, + onCountryChanged: (isoCode) => setState(() => _isoCode = isoCode), + onPickContact: () async {}, + onSubmit: _submit, + ); + } +}