Files
arcx-app/lib/features/profile/presentation/profile_edit_dialog.dart
T

158 lines
4.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:arcx/app/app_theme.dart';
import 'package:arcx/data/local/models/models.dart';
import 'package:arcx/features/profile/application/profile_controller.dart';
import 'package:arcx/features/profile/presentation/avatar_image.dart';
class ProfileEditDialog extends ConsumerStatefulWidget {
const ProfileEditDialog({super.key});
@override
ConsumerState<ProfileEditDialog> createState() => _ProfileEditDialogState();
}
class _ProfileEditDialogState extends ConsumerState<ProfileEditDialog> {
late final TextEditingController _controller;
bool _saving = false;
@override
void initState() {
super.initState();
final profile = ref.read(profileProvider).value;
_controller = TextEditingController(text: profile?.nickname ?? '');
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final profile = ref.watch(profileProvider).value;
return AlertDialog(
title: const Text('编辑个人资料'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
GestureDetector(
onTap: _saving ? null : () => _pickAvatar(context),
child: _AvatarPreview(profile: profile),
),
if (profile?.avatarSource == AvatarSource.localFile)
TextButton.icon(
onPressed: _saving ? null : _resetAvatar,
icon: const Icon(Icons.refresh, size: 18),
label: const Text('恢复默认头像'),
),
const SizedBox(height: 8),
TextField(
controller: _controller,
maxLength: 12,
decoration: const InputDecoration(
labelText: '昵称',
hintText: '1~12 个字符',
counterText: '',
),
),
],
),
),
actions: [
TextButton(
onPressed: _saving ? null : () => Navigator.pop(context),
child: const Text('取消'),
),
FilledButton(
onPressed: _saving ? null : _save,
child: const Text('保存'),
),
],
);
}
Future<void> _pickAvatar(BuildContext context) async {
final choice = await showModalBottomSheet<AvatarAction>(
context: context,
builder: (_) => SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
leading: const Icon(Icons.photo_outlined),
title: const Text('从相册选择'),
onTap: () => Navigator.pop(context, AvatarAction.gallery),
),
ListTile(
leading: const Icon(Icons.camera_alt_outlined),
title: const Text('拍摄照片'),
onTap: () => Navigator.pop(context, AvatarAction.camera),
),
],
),
),
);
if (choice == null) return;
setState(() => _saving = true);
await ref
.read(profileProvider.notifier)
.updateAvatar(fromCamera: choice == AvatarAction.camera);
if (mounted) setState(() => _saving = false);
}
Future<void> _resetAvatar() async {
setState(() => _saving = true);
await ref.read(profileProvider.notifier).resetAvatar();
if (mounted) setState(() => _saving = false);
}
Future<void> _save() async {
final name = _controller.text.trim();
if (name.isEmpty) {
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('昵称不能为空')));
return;
}
setState(() => _saving = true);
await ref.read(profileProvider.notifier).updateNickname(name);
if (mounted) {
setState(() => _saving = false);
Navigator.pop(context);
}
}
}
enum AvatarAction { gallery, camera }
class _AvatarPreview extends StatelessWidget {
const _AvatarPreview({required this.profile});
final UserProfile? profile;
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.bottomRight,
children: [
CircleAvatar(
radius: 44,
backgroundColor: AppTheme.surfaceMuted,
backgroundImage: resolveAvatarImage(profile),
),
Container(
padding: const EdgeInsets.all(6),
decoration: const BoxDecoration(
color: AppTheme.primary,
shape: BoxShape.circle,
),
child: const Icon(Icons.edit, color: Colors.white, size: 16),
),
],
);
}
}