261 lines
7.8 KiB
Dart
261 lines
7.8 KiB
Dart
// ============================================================
|
||
// 闲言APP — 会话模型
|
||
// 创建时间: 2026-05-01
|
||
// 更新时间: 2026-06-01
|
||
// 作用: 发现页面会话列表数据模型,支持置顶/隐藏/备注/已读/免打扰
|
||
// 上次更新: 添加ChatSessionL10n扩展,支持会话名称/描述实时多语言解析
|
||
// ============================================================
|
||
|
||
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,
|
||
});
|
||
|
||
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;
|
||
|
||
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,
|
||
}) {
|
||
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,
|
||
);
|
||
}
|
||
}
|
||
|
||
/// 系统会话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 all = {
|
||
readlater,
|
||
discover,
|
||
footprint,
|
||
dailyCard,
|
||
template,
|
||
readingReport,
|
||
weather,
|
||
poetry,
|
||
countdown,
|
||
dailyFortune,
|
||
solarTerm,
|
||
knowledgeGraph,
|
||
studyPlan,
|
||
progress,
|
||
fileTransfer,
|
||
rssFeed,
|
||
translate,
|
||
leisure,
|
||
};
|
||
|
||
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);
|
||
|
||
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;
|
||
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;
|
||
default:
|
||
return null;
|
||
}
|
||
}
|
||
}
|