- 清理大量废弃的 barrel 导出文件,移除冗余的中间导出层 - 修复所有相对路径导入错误,统一调整为扁平化模块引用 - 更新多平台 pubspec 版本号与依赖库版本 - 补充后端功能问题管理后台与脚本工具 - 调整部分页面的快捷方式文案适配新功能 - 更新部分翻译覆盖率与API文档
144 lines
4.5 KiB
Dart
144 lines
4.5 KiB
Dart
// ============================================================
|
||
// 闲言APP — 最近路由服务(单一数据源)
|
||
// 创建时间: 2026-05-24
|
||
// 更新时间: 2026-06-12
|
||
// 作用: 统一管理最近访问路由和自定义路由,消除KvStorage双写问题
|
||
// 上次更新: 从 navigation/ 子目录上移至 services/ 目录
|
||
// ============================================================
|
||
|
||
import 'dart:convert';
|
||
|
||
import 'package:xianyan/core/storage/kv_storage.dart';
|
||
import 'package:xianyan/core/utils/logger.dart';
|
||
import 'package:xianyan/core/utils/safe_json.dart';
|
||
|
||
class RecentRouteService {
|
||
static const _kRecentRoutes = 'tool_center_recent_routes';
|
||
static const _kCustomRoute = 'tool_center_custom_route';
|
||
static const _kRouteCounts = 'tool_center_route_counts';
|
||
static const _maxRecentCount = 10;
|
||
|
||
/// 已知的动态路由前缀,归一化时截取到此前缀长度
|
||
static const _dynamicRoutePrefixes = <String>[
|
||
'/chat-flow/',
|
||
'/chat-settings/',
|
||
'/article/',
|
||
'/category/',
|
||
'/user/',
|
||
'/weather/',
|
||
'/poetry/',
|
||
'/daily-fortune/',
|
||
'/tool/',
|
||
'/about/',
|
||
'/transfer-chat/',
|
||
];
|
||
|
||
/// 归一化路由:将动态段路由转换为基础路由
|
||
/// 例如 /chat-flow/123 → /chat-flow, /editor?text=xxx → /editor
|
||
static String _normalizeRoute(String route) {
|
||
var normalized = route;
|
||
final queryIndex = normalized.indexOf('?');
|
||
if (queryIndex > 0) {
|
||
normalized = normalized.substring(0, queryIndex);
|
||
}
|
||
for (final prefix in _dynamicRoutePrefixes) {
|
||
if (normalized.startsWith(prefix) && normalized.length > prefix.length) {
|
||
return prefix.substring(0, prefix.length - 1);
|
||
}
|
||
}
|
||
if (normalized.endsWith('/') && normalized.length > 1) {
|
||
normalized = normalized.substring(0, normalized.length - 1);
|
||
}
|
||
return normalized;
|
||
}
|
||
|
||
static List<String> getRecentRoutes() {
|
||
try {
|
||
final raw = KvStorage.getString(_kRecentRoutes);
|
||
if (raw != null && raw.isNotEmpty) {
|
||
final decoded = jsonDecode(raw) as List<dynamic>;
|
||
return decoded.map((e) => e.toString()).toList();
|
||
}
|
||
} catch (e) {
|
||
Log.w('最近路由: 读取失败 $e');
|
||
}
|
||
return [];
|
||
}
|
||
|
||
static Future<void> addRecentRoute(String route) async {
|
||
final normalized = _normalizeRoute(route);
|
||
if (normalized.isEmpty || normalized == '/' || normalized.startsWith('/onboarding')) return;
|
||
try {
|
||
final updated = List<String>.from(getRecentRoutes())
|
||
..remove(normalized)
|
||
..insert(0, normalized);
|
||
if (updated.length > _maxRecentCount) {
|
||
updated.removeRange(_maxRecentCount, updated.length);
|
||
}
|
||
await KvStorage.setString(_kRecentRoutes, jsonEncode(updated));
|
||
_incrementRouteCount(normalized);
|
||
} catch (e) {
|
||
Log.w('最近路由: 记录失败 $e');
|
||
}
|
||
}
|
||
|
||
static String? getCustomRoute() {
|
||
try {
|
||
return KvStorage.getString(_kCustomRoute);
|
||
} catch (e) {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
static Future<void> setCustomRoute(String route) async {
|
||
try {
|
||
await KvStorage.setString(_kCustomRoute, route);
|
||
} catch (e) {
|
||
Log.e('最近路由: 保存自定义路由失败 $e');
|
||
}
|
||
}
|
||
|
||
/// 删除指定路由(归一化后匹配)
|
||
static Future<void> removeRecentRoute(String route) async {
|
||
final normalized = _normalizeRoute(route);
|
||
try {
|
||
final updated = List<String>.from(getRecentRoutes())..remove(normalized);
|
||
await KvStorage.setString(_kRecentRoutes, jsonEncode(updated));
|
||
Log.i('最近路由: 删除 → $normalized');
|
||
} catch (e) {
|
||
Log.w('最近路由: 删除失败 $e');
|
||
}
|
||
}
|
||
|
||
static Map<String, int> getRouteCounts() {
|
||
try {
|
||
final raw = KvStorage.getString(_kRouteCounts);
|
||
if (raw != null && raw.isNotEmpty) {
|
||
final decoded = jsonDecode(raw) as Map<String, dynamic>;
|
||
return decoded.map((k, v) => MapEntry(k, SafeJson.parseInt(v)));
|
||
}
|
||
} catch (e) {
|
||
Log.w('最近路由: 读取访问次数失败 $e');
|
||
}
|
||
return {};
|
||
}
|
||
|
||
static List<String> getFrequentRoutes() {
|
||
final counts = getRouteCounts();
|
||
if (counts.isEmpty) return getRecentRoutes();
|
||
final sorted = counts.entries.toList()
|
||
..sort((a, b) => b.value.compareTo(a.value));
|
||
return sorted.map((e) => e.key).toList();
|
||
}
|
||
|
||
static void _incrementRouteCount(String route) {
|
||
try {
|
||
final counts = getRouteCounts();
|
||
counts[route] = (counts[route] ?? 0) + 1;
|
||
KvStorage.setString(_kRouteCounts, jsonEncode(counts));
|
||
} catch (e) {
|
||
Log.w('最近路由: 更新访问次数失败 $e');
|
||
}
|
||
}
|
||
}
|