chore: 完成v5.10.0版本迭代更新

此版本包含多项功能优化与修复:
1. 新增鸿蒙分层图标生成脚本,完善鸿蒙应用图标适配
2. 重构多处FutureProvider为NotifierProvider,修复ElementWithFuture异常
3. 更新flutter_tts依赖为鸿蒙适配版本,调整pubspec配置
4. 优化运势卡片样式文案,更新引导页功能介绍详情
5. 修复在线TTS服务Path正则匹配问题,支持含点号的路径
6. 重构通知权限、崩溃监控等状态管理逻辑
7. 更新翻译覆盖率统计,支持手动标注真实翻译进度
8. 优化编辑器工具栏、会话流页面交互细节
9. 新增日志筛选、导出CSV等增强功能
10. 调整设置页面文案,优化用户操作体验
This commit is contained in:
Developer
2026-05-26 08:24:44 +08:00
parent d2bd53f3bc
commit 3e68f7dc2a
166 changed files with 12377 additions and 4645 deletions

View File

@@ -1,9 +1,9 @@
/// ============================================================
/// 闲言APP — 统一存储抽象层
/// 创建时间: 2026-05-25
/// 更新时间: 2026-05-25
/// 更新时间: 2026-05-26
/// 作用: 统一KvStorage/SecureStorage的存储访问入口按功能域分组
/// 上次更新: 初始创建
/// 上次更新: LockStorage增加生物识别启用存储
/// ============================================================
import 'kv_storage.dart';
@@ -61,6 +61,7 @@ class LockStorage {
static const _keyEnabled = 'general_app_lock';
static const _keyMethod = 'app_lock_method';
static const _keyBiometricEnabled = 'app_lock_biometric_enabled';
static const _keyPattern = 'app_lock_pattern';
static const _keyPin = 'app_lock_pin';
static const _keyHintCode = 'app_lock_hint_code';
@@ -77,6 +78,12 @@ class LockStorage {
void writeMethodId(String id) => KvStorage.setString(_keyMethod, id);
bool readBiometricEnabled() =>
KvStorage.getBool(_keyBiometricEnabled) ?? false;
void writeBiometricEnabled(bool v) =>
KvStorage.setBool(_keyBiometricEnabled, v);
int readFailedAttempts() =>
KvStorage.getInt(_keyFailedAttempts) ?? 0;
@@ -121,6 +128,7 @@ class LockStorage {
await SecureStorage.delete(_keyPattern);
await SecureStorage.delete(_keyPin);
writeMethodId('none');
writeBiometricEnabled(false);
writeEnabled(false);
}

View File

@@ -1,11 +1,32 @@
/// ============================================================
/// 闲言APP — 缓存配置模型
/// 创建时间: 2026-04-28
/// 更新时间: 2026-05-23
/// 更新时间: 2026-05-26
/// 作用: 定义缓存策略配置,支持离线模式、预加载、缓存上限等
/// 上次更新: preloadChannels改用后端英文key(all/poetry/wisdom)
/// 上次更新: 新增智能预加载策略字段(preloadMode/preloadContentTypes/preloadFrequency/batteryThreshold)
/// ============================================================
/// 预加载模式
enum PreloadMode {
smart,
wifiOnly,
disabled,
}
/// 预加载内容类型
enum PreloadContentType {
text,
image,
audio,
}
/// 预加载频率
enum PreloadFrequency {
realtime,
hourly,
daily,
}
class CacheConfig {
final bool offlineModeEnabled;
final bool preloadOnWifi;
@@ -16,6 +37,18 @@ class CacheConfig {
final int maxRetryCount;
final Set<String> preloadChannels;
/// 预加载模式: smart(智能)/wifiOnly(仅WiFi)/disabled(关闭)
final PreloadMode preloadMode;
/// 预加载内容类型集合
final Set<PreloadContentType> preloadContentTypes;
/// 预加载频率: realtime(实时)/hourly(每小时)/daily(每天)
final PreloadFrequency preloadFrequency;
/// 低电量阈值百分比,低于此值暂停预加载
final int batteryThreshold;
const CacheConfig({
this.offlineModeEnabled = true,
this.preloadOnWifi = true,
@@ -25,6 +58,13 @@ class CacheConfig {
this.maxOfflineActions = 100,
this.maxRetryCount = 3,
this.preloadChannels = const {'all', 'poetry', 'wisdom'},
this.preloadMode = PreloadMode.smart,
this.preloadContentTypes = const {
PreloadContentType.text,
PreloadContentType.image,
},
this.preloadFrequency = PreloadFrequency.hourly,
this.batteryThreshold = 20,
});
CacheConfig copyWith({
@@ -36,6 +76,10 @@ class CacheConfig {
int? maxOfflineActions,
int? maxRetryCount,
Set<String>? preloadChannels,
PreloadMode? preloadMode,
Set<PreloadContentType>? preloadContentTypes,
PreloadFrequency? preloadFrequency,
int? batteryThreshold,
}) {
return CacheConfig(
offlineModeEnabled: offlineModeEnabled ?? this.offlineModeEnabled,
@@ -46,6 +90,10 @@ class CacheConfig {
maxOfflineActions: maxOfflineActions ?? this.maxOfflineActions,
maxRetryCount: maxRetryCount ?? this.maxRetryCount,
preloadChannels: preloadChannels ?? this.preloadChannels,
preloadMode: preloadMode ?? this.preloadMode,
preloadContentTypes: preloadContentTypes ?? this.preloadContentTypes,
preloadFrequency: preloadFrequency ?? this.preloadFrequency,
batteryThreshold: batteryThreshold ?? this.batteryThreshold,
);
}
@@ -58,6 +106,11 @@ class CacheConfig {
'maxOfflineActions': maxOfflineActions,
'maxRetryCount': maxRetryCount,
'preloadChannels': preloadChannels.toList(),
'preloadMode': preloadMode.name,
'preloadContentTypes':
preloadContentTypes.map((e) => e.name).toList(),
'preloadFrequency': preloadFrequency.name,
'batteryThreshold': batteryThreshold,
};
factory CacheConfig.fromJson(Map<String, dynamic> json) => CacheConfig(
@@ -72,5 +125,50 @@ class CacheConfig {
?.map((e) => e.toString())
.toSet() ??
const {'all', 'poetry', 'wisdom'},
preloadMode: _parsePreloadMode(json['preloadMode'] as String?),
preloadContentTypes: _parseContentTypes(
json['preloadContentTypes'] as List<dynamic>?,
),
preloadFrequency:
_parsePreloadFrequency(json['preloadFrequency'] as String?),
batteryThreshold: json['batteryThreshold'] as int? ?? 20,
);
static PreloadMode _parsePreloadMode(String? value) {
switch (value) {
case 'wifiOnly':
return PreloadMode.wifiOnly;
case 'disabled':
return PreloadMode.disabled;
default:
return PreloadMode.smart;
}
}
static Set<PreloadContentType> _parseContentTypes(List<dynamic>? values) {
if (values == null || values.isEmpty) {
return const {PreloadContentType.text, PreloadContentType.image};
}
return values.map((e) {
switch (e.toString()) {
case 'image':
return PreloadContentType.image;
case 'audio':
return PreloadContentType.audio;
default:
return PreloadContentType.text;
}
}).toSet();
}
static PreloadFrequency _parsePreloadFrequency(String? value) {
switch (value) {
case 'realtime':
return PreloadFrequency.realtime;
case 'daily':
return PreloadFrequency.daily;
default:
return PreloadFrequency.hourly;
}
}
}

View File

@@ -658,7 +658,7 @@ class AppDatabase extends _$AppDatabase {
}
Future<void> _markMigrationExecuted(int version) async {
await into(schemaMigrations).insert(
await into(schemaMigrations).insertOnConflictUpdate(
SchemaMigrationsCompanion(
version: Value(version),
executedAt: Value(DateTime.now()),