Files
xianyan/lib/features/discover/models/chat_session.dart
Developer 016ad3cea1 feat: 新增CTC云端笔记仓库功能
- 新增多语言国际化文案支持笔记仓库模块
- 配置Universal Links与App Links支持ctc.s2ss.com域名跳转
- 实现CTS会话入口与会话时间更新逻辑
- 新增CTC笔记完整服务栈:API客户端、本地存储、同步服务
- 新增笔记编辑、预览、冲突解决、版本对比组件
- 新增二维码扫码/分享功能与路由配置
- 修复UrlAnalyzerService调用参数冗余问题
- 修复ProfileHeader组件样式问题
- 统一macOS部署目标版本为13.0
- 抑制liquid_glass_widgets高频调试日志
2026-06-11 08:46:46 +08:00

322 lines
10 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ============================================================
// 闲言APP — 会话模型
// 创建时间: 2026-05-01
// 更新时间: 2026-06-08
// 作用: 发现页面会话列表数据模型,支持置顶/隐藏/备注/已读/免打扰
// 上次更新: 添加systemIcon getter系统会话使用CupertinoIcons替代emoji
// ============================================================
import 'package:flutter/cupertino.dart';
import 'package:xianyan/l10n/types/t_discover_base.dart';
enum ChatSessionType {
chat('chat', '会话流'),
discover('discover', '发现'),
footprint('footprint', '足迹'),
custom('custom', '自定义'),
readlater('readlater', '稍后读');
const ChatSessionType(this.id, this.label);
final String id;
final String label;
}
class ChatSession {
const ChatSession({
required this.id,
required this.type,
required this.emoji,
required this.name,
required this.lastMessage,
required this.lastTime,
this.remark,
this.isPinned = false,
this.isHidden = false,
this.unreadCount = 0,
this.isMuted = false,
this.route,
this.tag,
this.subtitle,
this.linkedNoteId,
});
final String id;
final ChatSessionType type;
final String emoji;
final String name;
final String lastMessage;
final DateTime lastTime;
final String? remark;
final bool isPinned;
final bool isHidden;
final int unreadCount;
final bool isMuted;
final String? route;
final String? tag;
final String? subtitle;
/// 关联的笔记ID用于"在发现中置顶"功能
final int? linkedNoteId;
/// 是否为置顶笔记会话
bool get isPinnedNote => linkedNoteId != null;
String get displayName => remark ?? name;
String get displayTime {
final now = DateTime.now();
final today = DateTime(now.year, now.month, now.day);
final yesterday = today.subtract(const Duration(days: 1));
final msgDate = DateTime(lastTime.year, lastTime.month, lastTime.day);
if (msgDate == today) {
return '${lastTime.hour.toString().padLeft(2, '0')}:${lastTime.minute.toString().padLeft(2, '0')}';
} else if (msgDate == yesterday) {
return '昨天';
} else if (lastTime.year == now.year) {
return '${lastTime.month.toString().padLeft(2, '0')}/${lastTime.day.toString().padLeft(2, '0')}';
} else {
return '${lastTime.year}/${lastTime.month.toString().padLeft(2, '0')}/${lastTime.day.toString().padLeft(2, '0')}';
}
}
ChatSession copyWith({
String? id,
ChatSessionType? type,
String? emoji,
String? name,
String? lastMessage,
DateTime? lastTime,
String? remark,
bool? isPinned,
bool? isHidden,
int? unreadCount,
bool? isMuted,
String? route,
String? tag,
String? subtitle,
int? linkedNoteId,
bool clearLinkedNoteId = false,
}) {
return ChatSession(
id: id ?? this.id,
type: type ?? this.type,
emoji: emoji ?? this.emoji,
name: name ?? this.name,
lastMessage: lastMessage ?? this.lastMessage,
lastTime: lastTime ?? this.lastTime,
remark: remark ?? this.remark,
isPinned: isPinned ?? this.isPinned,
isHidden: isHidden ?? this.isHidden,
unreadCount: unreadCount ?? this.unreadCount,
isMuted: isMuted ?? this.isMuted,
route: route ?? this.route,
tag: tag ?? this.tag,
subtitle: subtitle ?? this.subtitle,
linkedNoteId: clearLinkedNoteId ? null : (linkedNoteId ?? this.linkedNoteId),
);
}
}
/// 系统会话ID常量唯一权威定义Provider层引用此处
class SystemSessionIds {
static const readlater = 'readlater';
static const discover = 'discover';
static const footprint = 'footprint';
static const dailyCard = 'daily_card';
static const template = 'template';
static const readingReport = 'reading_report';
static const weather = 'weather';
static const poetry = 'poetry';
static const countdown = 'countdown';
static const dailyFortune = 'daily_fortune';
static const solarTerm = 'solar_term';
static const knowledgeGraph = 'knowledge_graph';
static const studyPlan = 'study_plan';
static const progress = 'progress';
static const fileTransfer = 'file_transfer';
static const rssFeed = 'rss_feed';
static const translate = 'translate';
static const leisure = 'leisure';
static const ctcNoteRepo = 'ctc_note_repo';
static const all = {
readlater,
discover,
footprint,
dailyCard,
template,
readingReport,
weather,
poetry,
countdown,
dailyFortune,
solarTerm,
knowledgeGraph,
studyPlan,
progress,
fileTransfer,
rssFeed,
translate,
leisure,
ctcNoteRepo,
};
static bool isSystem(String id) => all.contains(id);
}
/// 会话多语言扩展 — 在UI层实时解析翻译切换语言时自动响应
extension ChatSessionL10n on ChatSession {
/// 获取本地化的显示名称(优先使用备注,其次使用翻译名)
String localizedName(TDiscoverBase t) {
if (remark != null && remark!.isNotEmpty) return remark!;
final translated = _resolveName(t);
return translated ?? name;
}
/// 获取本地化的描述/最后消息
String localizedLastMessage(TDiscoverBase t) {
final translated = _resolveDesc(t);
return translated ?? lastMessage;
}
/// 获取本地化的副标题
String localizedSubtitle(TDiscoverBase t) {
final translated = _resolveDesc(t);
return translated ?? subtitle ?? lastMessage;
}
/// 是否为系统会话(需要翻译)
bool get isSystemSession => SystemSessionIds.isSystem(id);
/// 系统会话对应的 CupertinoIcon非系统会话返回 null
IconData? get systemIcon {
switch (id) {
case SystemSessionIds.readlater:
return CupertinoIcons.book_fill;
case SystemSessionIds.discover:
return CupertinoIcons.lightbulb_fill;
case SystemSessionIds.footprint:
return CupertinoIcons.location_fill;
case SystemSessionIds.dailyCard:
return CupertinoIcons.calendar;
case SystemSessionIds.template:
return CupertinoIcons.paintbrush_fill;
case SystemSessionIds.readingReport:
return CupertinoIcons.chart_bar_fill;
case SystemSessionIds.weather:
return CupertinoIcons.cloud_sun_fill;
case SystemSessionIds.poetry:
return CupertinoIcons.doc_text_fill;
case SystemSessionIds.dailyFortune:
return CupertinoIcons.star_circle_fill;
case SystemSessionIds.solarTerm:
return CupertinoIcons.tree;
case SystemSessionIds.knowledgeGraph:
return CupertinoIcons.link_circle_fill;
case SystemSessionIds.studyPlan:
return CupertinoIcons.book_circle_fill;
case SystemSessionIds.progress:
return CupertinoIcons.gauge;
case SystemSessionIds.fileTransfer:
return CupertinoIcons.folder_fill;
case SystemSessionIds.rssFeed:
return CupertinoIcons.antenna_radiowaves_left_right;
case SystemSessionIds.translate:
return CupertinoIcons.globe;
case SystemSessionIds.leisure:
return CupertinoIcons.sparkles;
case SystemSessionIds.ctcNoteRepo:
return CupertinoIcons.doc_text_search;
default:
return null;
}
}
String? _resolveName(TDiscoverBase t) {
switch (id) {
case SystemSessionIds.readlater:
return t.sessionReadLater;
case SystemSessionIds.discover:
return t.sessionInspiration;
case SystemSessionIds.footprint:
return t.sessionFootprint;
case SystemSessionIds.dailyCard:
return t.sessionDailyCard;
case SystemSessionIds.template:
return t.sessionTemplate;
case SystemSessionIds.readingReport:
return t.sessionReadingReport;
case SystemSessionIds.weather:
return t.sessionWeather;
case SystemSessionIds.poetry:
return t.sessionPoetry;
case SystemSessionIds.dailyFortune:
return t.sessionDailyFortune;
case SystemSessionIds.solarTerm:
return t.sessionSolarTerm;
case SystemSessionIds.knowledgeGraph:
return t.sessionKnowledgeGraph;
case SystemSessionIds.studyPlan:
return t.sessionStudyPlan;
case SystemSessionIds.progress:
return t.sessionProgress;
case SystemSessionIds.fileTransfer:
return t.sessionFileTransfer;
case SystemSessionIds.rssFeed:
return t.sessionRssFeed;
case SystemSessionIds.translate:
return t.sessionTranslate;
case SystemSessionIds.leisure:
return t.sessionLeisure;
case SystemSessionIds.ctcNoteRepo:
return t.sessionCtcNoteRepo;
default:
return null;
}
}
String? _resolveDesc(TDiscoverBase t) {
switch (id) {
case SystemSessionIds.readlater:
return t.sessionReadLaterDesc;
case SystemSessionIds.discover:
return t.sessionInspirationDesc;
case SystemSessionIds.footprint:
return t.sessionFootprintDesc;
case SystemSessionIds.dailyCard:
return t.sessionDailyCardDesc;
case SystemSessionIds.template:
return t.sessionTemplateDesc;
case SystemSessionIds.readingReport:
return t.sessionReadingReportDesc;
case SystemSessionIds.weather:
return t.sessionWeatherDesc;
case SystemSessionIds.poetry:
return t.sessionPoetryDesc;
case SystemSessionIds.dailyFortune:
return t.sessionDailyFortuneDesc;
case SystemSessionIds.solarTerm:
return t.sessionSolarTermDesc;
case SystemSessionIds.knowledgeGraph:
return t.sessionKnowledgeGraphDesc;
case SystemSessionIds.studyPlan:
return t.sessionStudyPlanDesc;
case SystemSessionIds.progress:
return t.sessionProgressDesc;
case SystemSessionIds.fileTransfer:
return t.sessionFileTransferDesc;
case SystemSessionIds.rssFeed:
return t.sessionRssFeedDesc;
case SystemSessionIds.translate:
return t.sessionTranslateDesc;
case SystemSessionIds.leisure:
return t.sessionLeisureDesc;
case SystemSessionIds.ctcNoteRepo:
return t.sessionCtcNoteRepoDesc;
default:
return null;
}
}
}