feat(block-phone): add edit contact functionality
This commit is contained in:
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
);
|
||||
|
||||
@@ -80,6 +80,37 @@ class BlockPhoneViewModel extends Notifier<BlockPhoneViewState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> 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<void> removeContact(int index) async {
|
||||
state = state.copyWith(isSaving: true, errorMessage: '');
|
||||
|
||||
|
||||
@@ -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<void>(
|
||||
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<void> _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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user