126 lines
5.2 KiB
Dart
126 lines
5.2 KiB
Dart
import 'dart:convert';
|
||
|
||
import 'package:hgdj/hj_model/home/collection_model.dart';
|
||
import 'package:hgdj/hj_model/video_model.dart';
|
||
import 'package:hgdj/hj_utils/const.dart';
|
||
import 'package:hgdj/tools_base/cache/history/base_history_record_store.dart';
|
||
import 'package:hgdj/tools_base/cache/history/cartoon_history_store.dart';
|
||
import 'package:hgdj/tools_base/cache/history/comics_history_store.dart';
|
||
import 'package:hgdj/tools_base/cache/history/community_history_store.dart';
|
||
import 'package:hgdj/tools_base/cache/history/game_history_store.dart';
|
||
import 'package:hgdj/tools_base/cache/history/novel_history_store.dart';
|
||
import 'package:hgdj/tools_base/cache/history/pic_history_store.dart';
|
||
import 'package:hgdj/tools_base/cache/history/search_history_store.dart';
|
||
import 'package:hgdj/tools_base/cache/history/short_video_history_store.dart';
|
||
import 'package:hgdj/tools_base/cache/history/video_history_store.dart';
|
||
import 'package:hgdj/tools_base/debug_log.dart';
|
||
|
||
import '../hj_model/cartoon_media_info.dart';
|
||
|
||
/// 浏览历史 + 搜索历史的统一入口。按 [MediaStyle] 派发到各自的 store,业务层不直接碰 store
|
||
class HistoryUtil {
|
||
/// 每种类型独占一个 db 文件,store 自身是单例。返回 null = 该类型不记历史
|
||
static BaseHistoryRecordStore? _storeOf(MediaStyle type) => switch (type) {
|
||
MediaStyle.Video => VideoHistoryStore(),
|
||
MediaStyle.ShortVideo => ShortVideoHistoryStore(),
|
||
MediaStyle.Comics => ComicsHistoryStore(),
|
||
MediaStyle.Cartoon => CartoonHistoryStore(),
|
||
MediaStyle.Novel => NovelHistoryStore(),
|
||
MediaStyle.Community => CommunityHistoryStore(),
|
||
MediaStyle.Pic => PicHistoryStore(),
|
||
MediaStyle.Game => GameHistoryStore(),
|
||
// 短剧的观看历史和续播位置是同一张表,走 DramaResumeStore;其余是当前业务无浏览历史需求的类型
|
||
MediaStyle.Drama ||
|
||
MediaStyle.Area ||
|
||
MediaStyle.Seed ||
|
||
MediaStyle.Actress ||
|
||
MediaStyle.NakedChat ||
|
||
MediaStyle.GroupChat =>
|
||
null,
|
||
};
|
||
|
||
/// 插入浏览历史(已存在则刷新到最前;超上限自动删最旧,上限见 BaseHistoryRecordStore.maxRows)
|
||
static Future<void> insert(Object? model, MediaStyle type) async {
|
||
try {
|
||
final json = _toJson(model);
|
||
if (json == null) {
|
||
//类型没在 _toJson/_idOf 里登记 → 静默不记历史。入参是 Object? 编译期拦不住,只能靠日志暴露
|
||
debugLog('HistoryUtil.insert 未登记的类型', model?.runtimeType);
|
||
return;
|
||
}
|
||
final id = _idOf(model);
|
||
final store = _storeOf(type);
|
||
if (id == null || id.isEmpty || store == null) return;
|
||
await store.save(modelId: id, modelDataJson: jsonEncode(json));
|
||
} catch (e) {
|
||
debugLog('HistoryUtil.insert', e);
|
||
}
|
||
}
|
||
|
||
/// 删除单条浏览历史
|
||
static Future<void> delete(Object? model, MediaStyle type) async {
|
||
try {
|
||
final id = _idOf(model);
|
||
if (id == null) {
|
||
debugLog('HistoryUtil.delete 未登记的类型', model?.runtimeType);
|
||
return;
|
||
}
|
||
final store = _storeOf(type);
|
||
if (id.isEmpty || store == null) return;
|
||
await store.remove(id);
|
||
} catch (e) {
|
||
debugLog('HistoryUtil.delete', e);
|
||
}
|
||
}
|
||
|
||
/// 指定类型的浏览历史(按时间倒序,分页)。解析不出的条目直接丢弃,不让一条脏数据废掉整页
|
||
static Future<List<T>> fetch<T>(MediaStyle type,
|
||
{int page = 1, int pageSize = 20}) async {
|
||
try {
|
||
final store = _storeOf(type);
|
||
if (store == null) return <T>[];
|
||
final jsonList = await store.fetch(page: page, pageSize: pageSize);
|
||
return jsonList.map((e) => _fromJson<T>(e)).whereType<T>().toList();
|
||
} catch (e) {
|
||
debugLog('HistoryUtil.fetch', e);
|
||
return <T>[];
|
||
}
|
||
}
|
||
|
||
/// 三个 _xxx 按实例匹配,新增可记历史的 model 时这里和 [_fromJson] 一起加一行
|
||
static String? _idOf(Object? model) => switch (model) {
|
||
VideoModel m => m.id,
|
||
CartoonMediaInfo m => m.id,
|
||
CollectionModel m => m.id,
|
||
_ => null,
|
||
};
|
||
|
||
static Map<String, dynamic>? _toJson(Object? model) => switch (model) {
|
||
VideoModel m => m.toJson(),
|
||
CartoonMediaInfo m => m.toJson(),
|
||
CollectionModel m => m.toJson(),
|
||
_ => null,
|
||
};
|
||
|
||
/// 反序列化只能按 [T] 分派(拿不到实例)。**必须用 T == 类型比较**:
|
||
/// 靠 T.toString() 对类名在 release 混淆后必然失配,表现是列表静默空白
|
||
static T? _fromJson<T>(String raw) {
|
||
final json = Map<String, dynamic>.from(jsonDecode(raw));
|
||
if (T == VideoModel) return VideoModel.fromJson(json) as T;
|
||
if (T == CartoonMediaInfo) return CartoonMediaInfo.fromJson(json) as T;
|
||
if (T == CollectionModel) return CollectionModel.fromJson(json) as T;
|
||
return null;
|
||
}
|
||
|
||
//搜索历史(按时间倒序)
|
||
static Future<List<String>> searchHistories() =>
|
||
SearchHistoryStore().fetchAll();
|
||
|
||
//新增一条搜索历史(已存在则去重提到最前,超上限自动删最旧)
|
||
static Future<void> addSearch(String keyword) =>
|
||
SearchHistoryStore().save(keyword);
|
||
|
||
//清空搜索历史
|
||
static Future<void> clearSearch() => SearchHistoryStore().clean();
|
||
}
|