Files
social-app/apps/lib/features/contacts/presentation/screens/add_contact_screen.dart
T

208 lines
6.1 KiB
Dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import '../../../../core/l10n/l10n.dart';
import '../../../../core/theme/design_tokens.dart';
import '../../../../shared/widgets/back_title_page_header.dart';
import '../../../../shared/widgets/app_input.dart';
import '../../../../shared/widgets/link_button.dart';
import '../../../../shared/widgets/toast/toast.dart';
import '../../../../shared/widgets/toast/toast_type.dart';
class AddContactScreen extends StatefulWidget {
final String? contactId;
const AddContactScreen({super.key, this.contactId});
@override
State<AddContactScreen> createState() => _AddContactScreenState();
}
class _AddContactScreenState extends State<AddContactScreen> {
final _nameController = TextEditingController();
final _phoneController = TextEditingController();
final _remarkController = TextEditingController();
bool get isEditing => widget.contactId != null;
@override
void dispose() {
_nameController.dispose();
_phoneController.dispose();
_remarkController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Scaffold(
backgroundColor: colorScheme.surfaceContainerLow,
resizeToAvoidBottomInset: false,
body: SafeArea(
maintainBottomViewPadding: true,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
BackTitlePageHeader(
title: isEditing
? context.l10n.contactEditTitle
: context.l10n.contactAddTitle,
onBack: () => context.pop(),
trailing: _buildConfirmButton(),
),
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.fromLTRB(20, 8, 20, 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildAvatarSection(),
const SizedBox(height: 14),
_buildFormCard(),
if (isEditing) ...[
const SizedBox(height: 14),
_buildDeleteRow(),
],
],
),
),
),
],
),
),
);
}
Widget _buildConfirmButton() {
final colorScheme = Theme.of(context).colorScheme;
return SizedBox(
width: AppSpacing.xxl * 2,
height: AppSpacing.xxl * 2,
child: TextButton(
onPressed: _handleConfirm,
style: TextButton.styleFrom(
padding: const EdgeInsets.all(AppSpacing.none),
backgroundColor: colorScheme.primaryContainer,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppRadius.full),
side: BorderSide(color: colorScheme.outlineVariant),
),
),
child: Icon(
Icons.check,
size: AppSpacing.lg,
color: colorScheme.primary,
),
),
);
}
Widget _buildAvatarSection() {
final colorScheme = Theme.of(context).colorScheme;
return Center(
child: Container(
width: 72,
height: 72,
decoration: BoxDecoration(
color: colorScheme.primaryContainer.withValues(alpha: 0.45),
borderRadius: BorderRadius.circular(36),
border: Border.all(color: colorScheme.surface.withValues(alpha: 0)),
),
child: Icon(Icons.person_outline, size: 24, color: colorScheme.outline),
),
);
}
Widget _buildFormCard() {
final colorScheme = Theme.of(context).colorScheme;
return Container(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: colorScheme.surface,
borderRadius: BorderRadius.circular(16),
border: Border.all(color: colorScheme.outlineVariant),
),
child: Column(
children: [
AppInput(
label: context.l10n.contactNickname,
hint: context.l10n.contactNicknameHint,
controller: _nameController,
),
const SizedBox(height: 14),
AppInput(
label: context.l10n.contactPhone,
hint: context.l10n.contactPhoneHint,
controller: _phoneController,
keyboardType: TextInputType.phone,
),
const SizedBox(height: 14),
AppInput(
label: context.l10n.contactRemark,
hint: context.l10n.contactRemarkHint,
controller: _remarkController,
maxLines: 3,
),
],
),
);
}
Widget _buildDeleteRow() {
final colorScheme = Theme.of(context).colorScheme;
return Padding(
padding: const EdgeInsets.only(bottom: AppSpacing.sm),
child: LinkButton(
text: context.l10n.contactDelete,
onTap: _handleDelete,
foregroundColor: colorScheme.error,
),
);
}
void _handleConfirm() {
final name = _nameController.text.trim();
final phone = _phoneController.text.trim();
if (name.isEmpty || phone.isEmpty) {
Toast.show(
context,
context.l10n.contactFillRequired,
type: ToastType.warning,
);
return;
}
// TODO: Implement save logic
context.pop();
}
void _handleDelete() {
final colorScheme = Theme.of(context).colorScheme;
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(context.l10n.contactDeleteConfirmTitle),
content: Text(context.l10n.contactDeleteConfirmMessage),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(context.l10n.commonCancel),
),
TextButton(
onPressed: () {
Navigator.pop(context);
// TODO: Implement delete logic
context.pop();
},
child: Text(
context.l10n.commonDelete,
style: TextStyle(color: colorScheme.error),
),
),
],
),
);
}
}