1. 全局替换tool_center/inspiration为discover模块,统一路由路径 2. 调整AppRoutes路由常量,将discover作为主Tab页,inspiration作为子页面 3. 更新页面注册表与路由配置,修正跳转目标 4. 调整启动页可选配置项,修正路由ID对应关系 5. 新增翻译服务、内容发现、热搜相关工具类与数据模型 6. 修复缓存清理后未刷新统计的问题,调整x86_64架构注释 7. 更新AGENTS.md文档约束规则 8. 新增一批调试用截图资源文件
176 lines
5.2 KiB
Dart
176 lines
5.2 KiB
Dart
/// ============================================================
|
|
/// 闲言APP — 聊天附件服务
|
|
/// 创建时间: 2026-05-08
|
|
/// 更新时间: 2026-05-08
|
|
/// 作用: 附件的创建/查询/删除/云端同步状态管理
|
|
/// 上次更新: 初始创建
|
|
/// ============================================================
|
|
|
|
import 'package:drift/drift.dart' show Value;
|
|
import 'package:uuid/uuid.dart';
|
|
|
|
import 'package:xianyan/core/storage/database/app_database.dart';
|
|
import 'package:xianyan/core/utils/logger.dart';
|
|
import 'chat_file_service.dart';
|
|
|
|
class ChatAttachmentService {
|
|
ChatAttachmentService._();
|
|
|
|
static final _db = AppDatabase.instance;
|
|
static const _uuid = Uuid();
|
|
|
|
/// 创建附件记录(文件已由 ChatFileService 保存)
|
|
static Future<ChatAttachment> create({
|
|
required String messageId,
|
|
required String conversationId,
|
|
required String fileName,
|
|
required String filePath,
|
|
required String fileType,
|
|
required int fileSize,
|
|
String? thumbnailPath,
|
|
int? width,
|
|
int? height,
|
|
int? durationMs,
|
|
}) async {
|
|
final id = _uuid.v4();
|
|
final att = ChatAttachmentsCompanion.insert(
|
|
id: id,
|
|
messageId: messageId,
|
|
conversationId: conversationId,
|
|
fileName: fileName,
|
|
filePath: filePath,
|
|
fileType: fileType,
|
|
fileSize: fileSize,
|
|
thumbnailPath: Value(thumbnailPath),
|
|
width: Value(width),
|
|
height: Value(height),
|
|
durationMs: Value(durationMs),
|
|
createdAt: DateTime.now(),
|
|
);
|
|
await _db.insertChatAttachment(att);
|
|
Log.d('附件记录已创建: $fileName ($id)');
|
|
return (await _db.getChatAttachments(messageId)).first;
|
|
}
|
|
|
|
/// 保存图片附件(含缩略图)
|
|
static Future<ChatAttachment> saveImageAttachment({
|
|
required String messageId,
|
|
required String conversationId,
|
|
required String fileName,
|
|
required String filePath,
|
|
required int fileSize,
|
|
String? thumbnailPath,
|
|
int? width,
|
|
int? height,
|
|
}) async {
|
|
return create(
|
|
messageId: messageId,
|
|
conversationId: conversationId,
|
|
fileName: fileName,
|
|
filePath: filePath,
|
|
fileType: 'image/${_getExtension(fileName)}',
|
|
fileSize: fileSize,
|
|
thumbnailPath: thumbnailPath,
|
|
width: width,
|
|
height: height,
|
|
);
|
|
}
|
|
|
|
/// 保存文件附件
|
|
static Future<ChatAttachment> saveFileAttachment({
|
|
required String messageId,
|
|
required String conversationId,
|
|
required String fileName,
|
|
required String filePath,
|
|
required int fileSize,
|
|
required String mimeType,
|
|
}) async {
|
|
return create(
|
|
messageId: messageId,
|
|
conversationId: conversationId,
|
|
fileName: fileName,
|
|
filePath: filePath,
|
|
fileType: mimeType,
|
|
fileSize: fileSize,
|
|
);
|
|
}
|
|
|
|
/// 获取消息的所有附件
|
|
static Future<List<ChatAttachment>> getByMessage(String messageId) {
|
|
return _db.getChatAttachments(messageId);
|
|
}
|
|
|
|
/// 获取会话的所有附件
|
|
static Future<List<ChatAttachment>> getByConversation(
|
|
String conversationId, {
|
|
int limit = 100,
|
|
}) {
|
|
return _db.getChatAttachmentsByConversation(conversationId, limit: limit);
|
|
}
|
|
|
|
/// 删除消息的附件(同时删除文件)
|
|
static Future<void> deleteByMessage(String messageId) async {
|
|
final attachments = await _db.getChatAttachments(messageId);
|
|
for (final att in attachments) {
|
|
await ChatFileService.deleteFile(att.filePath);
|
|
if (att.thumbnailPath != null) {
|
|
await ChatFileService.deleteFile(att.thumbnailPath!);
|
|
}
|
|
}
|
|
await _db.deleteChatAttachmentsByMessage(messageId);
|
|
Log.d('消息附件已删除: msg=$messageId');
|
|
}
|
|
|
|
/// 删除会话的所有附件(同时删除文件)
|
|
static Future<void> deleteByConversation(String conversationId) async {
|
|
final attachments = await _db.getChatAttachmentsByConversation(conversationId);
|
|
for (final att in attachments) {
|
|
await ChatFileService.deleteFile(att.filePath);
|
|
if (att.thumbnailPath != null) {
|
|
await ChatFileService.deleteFile(att.thumbnailPath!);
|
|
}
|
|
}
|
|
await _db.deleteChatAttachmentsByConversation(conversationId);
|
|
await ChatFileService.deleteConversationFiles(conversationId);
|
|
Log.d('会话附件已全部删除: conv=$conversationId');
|
|
}
|
|
|
|
/// 更新云端同步状态
|
|
static Future<void> updateCloudSync({
|
|
required String attachmentId,
|
|
required String cloudUrl,
|
|
}) async {
|
|
await _db.updateChatAttachment(
|
|
ChatAttachmentsCompanion(
|
|
id: Value(attachmentId),
|
|
cloudUrl: Value(cloudUrl),
|
|
cloudSyncedAt: Value(DateTime.now()),
|
|
),
|
|
);
|
|
}
|
|
|
|
/// 获取未同步的附件数量
|
|
static Future<int> getUnsyncedCount() {
|
|
return _db.getUnsyncedChatAttachmentCount();
|
|
}
|
|
|
|
/// 获取附件数量
|
|
static Future<int> getCount(String conversationId) {
|
|
return _db.getChatAttachmentCount(conversationId);
|
|
}
|
|
|
|
/// 获取附件的绝对路径
|
|
static Future<String> getAbsolutePath(String relativePath) {
|
|
return ChatFileService.getAbsolutePath(relativePath);
|
|
}
|
|
|
|
/// 获取扩展名
|
|
static String _getExtension(String fileName) {
|
|
final dotIndex = fileName.lastIndexOf('.');
|
|
if (dotIndex >= 0 && dotIndex < fileName.length - 1) {
|
|
return fileName.substring(dotIndex + 1).toLowerCase();
|
|
}
|
|
return 'jpg';
|
|
}
|
|
}
|