AI助手优化-头像和对话功能

This commit is contained in:
2026-09-29 09:45:02 +08:00
parent 80222099ff
commit f4ad2f8612
15 changed files with 990 additions and 37 deletions
+70 -8
View File
@@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:image_picker/image_picker.dart';
import '../../api/auth_api.dart';
import '../../core/module/app_module.dart';
import '../../core/network/api_exception.dart';
import '../../core/network/auth_redirect.dart';
@@ -12,6 +14,7 @@ import '../../providers/budget_provider.dart';
import '../../utils/amount_input_formatter.dart';
import '../../utils/amount_util.dart';
import '../../utils/toast.dart';
import '../../widgets/avatar.dart';
import '../../widgets/cute_icon.dart';
import '../../widgets/state_views.dart';
@@ -47,7 +50,7 @@ class MinePage extends ConsumerWidget {
physics: const AlwaysScrollableScrollPhysics(),
padding: const EdgeInsets.all(16),
children: [
_userCard(user?.nickname ?? '用户', user?.username ?? '-'),
_userCard(context, ref, user?.nickname ?? '用户', user?.username ?? '-'),
const SizedBox(height: 14),
_accountCard(context, ref, accountAsync),
const SizedBox(height: 14),
@@ -78,7 +81,9 @@ class MinePage extends ConsumerWidget {
future.then<void>((_) {}, onError: (_, _) {});
// ---------------- 用户信息 ----------------
Widget _userCard(String nickname, String username) {
Widget _userCard(BuildContext context, WidgetRef ref, String nickname, String username) {
final avatar = ref.watch(authProvider).user?.avatar;
return Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 24),
decoration: BoxDecoration(
@@ -97,12 +102,15 @@ class MinePage extends ConsumerWidget {
),
child: Row(
children: [
Container(
width: 60,
height: 60,
decoration: const BoxDecoration(shape: BoxShape.circle, color: Colors.white),
alignment: Alignment.center,
child: const CuteIcon('user', size: 32),
// 头像。点它换 —— 这是全 App 唯一的用户头像,聊天气泡用的也是它
GestureDetector(
onTap: () => _pickAvatar(context, ref),
child: Avatar(
assetPath: avatar,
size: 60,
fallbackIcon: 'user',
backgroundColor: Colors.white,
),
),
const SizedBox(width: 16),
Expanded(
@@ -125,11 +133,65 @@ class MinePage extends ConsumerWidget {
],
),
),
// 提示这个区域可点,不然没人知道能换头像
const Icon(Icons.chevron_right, size: 20, color: Color(0xFF6D4C41)),
],
),
);
}
/// 换头像:选图 → 上传 → 更新资料 → 刷新本地用户信息
Future<void> _pickAvatar(BuildContext context, WidgetRef ref) async {
final source = await showModalBottomSheet<ImageSource>(
context: context,
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
builder: (sheetContext) => SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
leading: const Icon(Icons.photo_camera_outlined, color: Color(0xFFC8956E)),
title: const Text('拍一张', style: TextStyle(fontSize: 14.5)),
onTap: () => Navigator.of(sheetContext).pop(ImageSource.camera),
),
ListTile(
leading: const Icon(Icons.photo_library_outlined, color: Color(0xFFC8956E)),
title: const Text('从相册选', style: TextStyle(fontSize: 14.5)),
onTap: () => Navigator.of(sheetContext).pop(ImageSource.gallery),
),
const SizedBox(height: 8),
],
),
),
);
if (source == null || !context.mounted) return;
final api = ref.read(authApiProvider);
try {
final picked = await ImagePicker().pickImage(
source: source,
imageQuality: 80,
maxWidth: 800,
);
if (picked == null || !context.mounted) return;
// 上传拿路径,再提交资料 —— 两步是为了「传了但没保存」不留下记录
final path = await api.uploadAvatar(picked.path);
final res = await api.updateProfile(avatar: path);
if (!context.mounted) return;
await ref.read(authProvider.notifier).updateUserFromResponse(res);
if (context.mounted) showToast(context, '头像已更新', icon: 'check');
} on ApiException catch (e) {
if (context.mounted) showToast(context, e.message, error: true);
} catch (e) {
if (context.mounted) showToast(context, '换头像失败:$e', error: true);
}
}
// ---------------- 账户卡 ----------------
Widget _accountCard(BuildContext context, WidgetRef ref, AsyncValue<AccountInfo> accountAsync) {
return Container(