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
+79
View File
@@ -0,0 +1,79 @@
import 'package:flutter/material.dart';
import '../core/network/api_env.dart';
import 'cute_icon.dart';
/// 圆形头像。全 App 只有这一个头像组件 —— 人设、用户、「我的」页面、聊天气泡都用它。
///
/// 三种输入都要兜住:
/// · [assetPath] 为空 → 画默认图标([fallbackIcon])
/// · 图片加载中 → 显示一个淡淡的占位圆
/// · 加载失败(后端文件被删了 / 网络断了)→ 退回默认图标,不显示裂图
///
/// 为什么不用 `CircleAvatar`:它的 backgroundImage 出错时不好接管,
/// 会有「裂图 + 背景色」的难看状态。自己用 [ClipOval] + [Image.network] 能完全控制。
class Avatar extends StatelessWidget {
const Avatar({
super.key,
this.assetPath,
this.size = 40,
this.fallbackIcon = 'user',
this.fallbackColor = const Color(0xFFC8956E),
this.backgroundColor = const Color(0xFFFFF3E6),
});
/// 后端返回的**相对路径**(如 `persona/2026/09/29/xxx.jpg`)。
/// 传空或 null → 用默认图标。
final String? assetPath;
final double size;
/// 没有头像时显示哪个小图标(`CuteIcon` 的名字)
final String fallbackIcon;
/// 默认图标的颜色
final Color fallbackColor;
/// 头像底圈的颜色
final Color backgroundColor;
@override
Widget build(BuildContext context) {
final path = assetPath?.trim() ?? '';
return Container(
width: size,
height: size,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: backgroundColor,
),
clipBehavior: Clip.antiAlias,
child: path.isEmpty ? _fallback() : _image(path),
);
}
Widget _fallback() {
return Center(
child: CuteIcon(fallbackIcon, size: size * 0.58),
);
}
Widget _image(String path) {
return Image.network(
resolveAssetUrl('/uploads/$path'),
fit: BoxFit.cover,
// 头像显示尺寸很小,限一下解码尺寸省内存 —— 原图可能是 400px
cacheWidth: (size * 3).round(),
loadingBuilder: (context, child, progress) {
// 还没加载出来时给个纯色圆,比空白或转圈干净
if (progress == null) return child;
return const SizedBox.shrink();
},
errorBuilder: (context, _, _) {
// 后端文件被删了也会走到这 —— 退回默认图标,不留裂图
return _fallback();
},
);
}
}