为 audioplayers_android 模块单独设置 Java 1.8,其他模块保持 Java 17
This commit is contained in:
@@ -32,7 +32,6 @@ class HistoryController {
|
||||
.map((item) => Map<String, dynamic>.from(item))
|
||||
.toList();
|
||||
} catch (e) {
|
||||
print('获取历史记录失败: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -42,57 +41,42 @@ class HistoryController {
|
||||
/// 如果诗词已存在,则不会重复添加
|
||||
/// 返回是否添加成功
|
||||
static Future<bool> addToHistory(Map<String, dynamic> poetryData) async {
|
||||
// 防止并发调用
|
||||
if (_isAdding) {
|
||||
print('正在添加历史记录,跳过重复调用: ${poetryData['name']}');
|
||||
return false;
|
||||
}
|
||||
|
||||
_isAdding = true;
|
||||
|
||||
try {
|
||||
print('开始添加历史记录: ${poetryData['name']} (ID: ${poetryData['id']})');
|
||||
|
||||
final historyJson = await SQLiteStorageController.getString(
|
||||
_historyKey,
|
||||
defaultValue: '[]',
|
||||
);
|
||||
final List<dynamic> historyList = json.decode(historyJson);
|
||||
|
||||
print('当前历史记录数量: ${historyList.length}');
|
||||
|
||||
// 检查是否已存在相同的诗词
|
||||
final existingIndex = historyList.indexWhere(
|
||||
(item) => item['id'] == poetryData['id'],
|
||||
);
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
print('诗词已存在于历史记录中: ${poetryData['name']} (索引: $existingIndex)');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 添加时间戳和日期
|
||||
final enrichedPoetryData = Map<String, dynamic>.from(poetryData);
|
||||
enrichedPoetryData['timestamp'] = DateTime.now().millisecondsSinceEpoch;
|
||||
enrichedPoetryData['date'] = DateTime.now().toString().split(' ')[0];
|
||||
|
||||
// 插入到列表开头
|
||||
historyList.insert(0, enrichedPoetryData);
|
||||
|
||||
// 保持最多指定数量的记录
|
||||
if (historyList.length > _maxHistoryCount) {
|
||||
historyList.removeRange(_maxHistoryCount, historyList.length);
|
||||
}
|
||||
|
||||
// 保存到本地存储
|
||||
final updatedHistoryJson = json.encode(historyList);
|
||||
await SQLiteStorageController.setString(_historyKey, updatedHistoryJson);
|
||||
|
||||
print('已添加到历史记录: ${poetryData['name']} (新数量: ${historyList.length})');
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('添加历史记录失败: $e');
|
||||
return false;
|
||||
} finally {
|
||||
_isAdding = false;
|
||||
@@ -104,8 +88,6 @@ class HistoryController {
|
||||
/// 返回是否移除成功
|
||||
static Future<bool> removeFromHistory(int poetryId) async {
|
||||
try {
|
||||
print('开始删除历史记录: 诗词ID $poetryId');
|
||||
|
||||
final historyJson = await SQLiteStorageController.getString(
|
||||
_historyKey,
|
||||
defaultValue: '[]',
|
||||
@@ -113,40 +95,21 @@ class HistoryController {
|
||||
final List<dynamic> historyList = json.decode(historyJson);
|
||||
|
||||
final originalLength = historyList.length;
|
||||
print('删除前历史记录数量: $originalLength');
|
||||
|
||||
// 查找匹配的记录
|
||||
final matchingItems = <int>[];
|
||||
for (int i = 0; i < historyList.length; i++) {
|
||||
if (historyList[i]['id'] == poetryId) {
|
||||
matchingItems.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
print('找到匹配的记录索引: $matchingItems');
|
||||
|
||||
// 移除指定ID的诗词
|
||||
historyList.removeWhere((item) => item['id'] == poetryId);
|
||||
|
||||
if (historyList.length < originalLength) {
|
||||
// 保存更新后的列表
|
||||
final updatedHistoryJson = json.encode(historyList);
|
||||
await SQLiteStorageController.setString(
|
||||
_historyKey,
|
||||
updatedHistoryJson,
|
||||
);
|
||||
|
||||
print(
|
||||
'已从历史记录中移除诗词ID: $poetryId (删除了 ${originalLength - historyList.length} 条记录,剩余 ${historyList.length} 条)',
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
print('未找到要删除的诗词ID: $poetryId');
|
||||
return false;
|
||||
} catch (e) {
|
||||
print('移除历史记录失败: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -156,44 +119,30 @@ class HistoryController {
|
||||
static Future<bool> clearHistory() async {
|
||||
try {
|
||||
await SQLiteStorageController.remove(_historyKey);
|
||||
|
||||
print('已清空所有历史记录');
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('清空历史记录失败: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取历史记录数量
|
||||
/// 返回当前历史记录的总数
|
||||
static Future<int> getHistoryCount() async {
|
||||
try {
|
||||
final history = await getHistory();
|
||||
return history.length;
|
||||
} catch (e) {
|
||||
print('获取历史记录数量失败: $e');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// 检查诗词是否在历史记录中
|
||||
/// [poetryId] 要检查的诗词ID
|
||||
/// 返回是否存在
|
||||
static Future<bool> isInHistory(int poetryId) async {
|
||||
try {
|
||||
final history = await getHistory();
|
||||
return history.any((item) => item['id'] == poetryId);
|
||||
} catch (e) {
|
||||
print('检查历史记录失败: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 搜索历史记录
|
||||
/// [keyword] 搜索关键词
|
||||
/// 返回匹配的历史记录列表
|
||||
static Future<List<Map<String, dynamic>>> searchHistory(
|
||||
String keyword,
|
||||
) async {
|
||||
@@ -215,7 +164,6 @@ class HistoryController {
|
||||
introduce.contains(lowerKeyword);
|
||||
}).toList();
|
||||
} catch (e) {
|
||||
print('搜索历史记录失败: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -285,20 +233,15 @@ class HistoryController {
|
||||
'topDynasties': Map.fromEntries(sortedDynasties),
|
||||
};
|
||||
} catch (e) {
|
||||
print('获取历史记录统计失败: $e');
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/// 导出历史记录
|
||||
/// [format] 导出格式 ('json' | 'csv')
|
||||
/// 返回导出的字符串
|
||||
static Future<String> exportHistory({String format = 'json'}) async {
|
||||
try {
|
||||
final history = await getHistory();
|
||||
|
||||
if (format.toLowerCase() == 'csv') {
|
||||
// CSV格式导出
|
||||
final buffer = StringBuffer();
|
||||
buffer.writeln('ID,诗词名称,朝代,译文,原文,日期,时间戳');
|
||||
|
||||
@@ -310,11 +253,9 @@ class HistoryController {
|
||||
|
||||
return buffer.toString();
|
||||
} else {
|
||||
// JSON格式导出
|
||||
return json.encode(history);
|
||||
}
|
||||
} catch (e) {
|
||||
print('导出历史记录失败: $e');
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -336,38 +277,26 @@ class HistoryController {
|
||||
final List<dynamic> likedList = json.decode(likedJson);
|
||||
return likedList.map((item) => Map<String, dynamic>.from(item)).toList();
|
||||
} catch (e) {
|
||||
print('获取点赞列表失败: $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// 添加诗词到点赞列表
|
||||
/// [poetryData] 要保存的诗词数据
|
||||
/// 如果诗词已存在,则不会重复添加
|
||||
/// 返回是否添加成功
|
||||
static Future<bool> addToLiked(Map<String, dynamic> poetryData) async {
|
||||
try {
|
||||
print('开始添加点赞记录: ${poetryData['name']} (ID: ${poetryData['id']})');
|
||||
|
||||
final likedJson = await SQLiteStorageController.getString(
|
||||
_likedKey,
|
||||
defaultValue: '[]',
|
||||
);
|
||||
final List<dynamic> likedList = json.decode(likedJson);
|
||||
|
||||
print('当前点赞记录数量: ${likedList.length}');
|
||||
|
||||
// 检查是否已存在相同的诗词
|
||||
final existingIndex = likedList.indexWhere(
|
||||
(item) => item['id'] == poetryData['id'],
|
||||
);
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
print('诗词已存在于点赞记录中: ${poetryData['name']} (索引: $existingIndex)');
|
||||
return false;
|
||||
}
|
||||
|
||||
// 添加时间戳和日期
|
||||
final enrichedPoetryData = Map<String, dynamic>.from(poetryData);
|
||||
final now = DateTime.now();
|
||||
enrichedPoetryData['liked_timestamp'] = now.millisecondsSinceEpoch;
|
||||
@@ -375,29 +304,19 @@ class HistoryController {
|
||||
enrichedPoetryData['liked_time'] =
|
||||
'${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}';
|
||||
|
||||
// 插入到列表开头
|
||||
likedList.insert(0, enrichedPoetryData);
|
||||
|
||||
// 保存到本地存储
|
||||
final updatedLikedJson = json.encode(likedList);
|
||||
await SQLiteStorageController.setString(_likedKey, updatedLikedJson);
|
||||
|
||||
print('已添加到点赞记录: ${poetryData['name']} (新数量: ${likedList.length})');
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('添加点赞记录失败: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 从点赞列表中移除指定诗词
|
||||
/// [poetryId] 要移除的诗词ID
|
||||
/// 返回是否移除成功
|
||||
static Future<bool> removeLikedPoetry(String poetryId) async {
|
||||
try {
|
||||
print('开始删除点赞记录: 诗词ID $poetryId');
|
||||
|
||||
final likedJson = await SQLiteStorageController.getString(
|
||||
_likedKey,
|
||||
defaultValue: '[]',
|
||||
@@ -405,67 +324,45 @@ class HistoryController {
|
||||
final List<dynamic> likedList = json.decode(likedJson);
|
||||
|
||||
final originalLength = likedList.length;
|
||||
print('删除前点赞记录数量: $originalLength');
|
||||
|
||||
// 移除指定ID的诗词
|
||||
likedList.removeWhere((item) => item['id'].toString() == poetryId);
|
||||
|
||||
if (likedList.length < originalLength) {
|
||||
// 保存更新后的列表
|
||||
final updatedLikedJson = json.encode(likedList);
|
||||
await SQLiteStorageController.setString(_likedKey, updatedLikedJson);
|
||||
|
||||
print(
|
||||
'已从点赞记录中移除诗词ID: $poetryId (删除了 ${originalLength - likedList.length} 条记录,剩余 ${likedList.length} 条)',
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
print('未找到要删除的诗词ID: $poetryId');
|
||||
return false;
|
||||
} catch (e) {
|
||||
print('移除点赞记录失败: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 检查诗词是否在点赞列表中
|
||||
/// [poetryId] 要检查的诗词ID
|
||||
/// 返回是否存在
|
||||
static Future<bool> isInLiked(String poetryId) async {
|
||||
try {
|
||||
final likedList = await getLikedHistory();
|
||||
return likedList.any((item) => item['id'].toString() == poetryId);
|
||||
} catch (e) {
|
||||
print('检查点赞记录失败: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 清空所有点赞记录
|
||||
/// 返回是否清空成功
|
||||
static Future<bool> clearLikedHistory() async {
|
||||
try {
|
||||
await SQLiteStorageController.remove(_likedKey);
|
||||
|
||||
print('已清空所有点赞记录');
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('清空点赞记录失败: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取点赞记录数量
|
||||
/// 返回当前点赞记录的总数
|
||||
static Future<int> getLikedCount() async {
|
||||
try {
|
||||
final likedList = await getLikedHistory();
|
||||
return likedList.length;
|
||||
} catch (e) {
|
||||
print('获取点赞记录数量失败: $e');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -510,7 +407,6 @@ class HistoryController {
|
||||
|
||||
return notes;
|
||||
} catch (e) {
|
||||
print('获取笔记列表失败: $e');
|
||||
return _getDefaultNotes();
|
||||
}
|
||||
}
|
||||
@@ -635,16 +531,12 @@ class HistoryController {
|
||||
final notesJson = json.encode(notes);
|
||||
await SQLiteStorageController.setString(_notesKey, notesJson);
|
||||
|
||||
print('保存笔记成功: $id, 置顶: $pinned, 锁定: $locked, 分类: $cat');
|
||||
return id;
|
||||
} catch (e) {
|
||||
print('保存笔记失败: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取单个笔记
|
||||
/// [noteId] 笔记ID
|
||||
static Future<Map<String, dynamic>?> getNote(String noteId) async {
|
||||
try {
|
||||
final notes = await getNotes();
|
||||
@@ -653,7 +545,6 @@ class HistoryController {
|
||||
orElse: () => <String, dynamic>{},
|
||||
);
|
||||
} catch (e) {
|
||||
print('获取笔记失败: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -668,24 +559,18 @@ class HistoryController {
|
||||
final notesJson = json.encode(notes);
|
||||
await SQLiteStorageController.setString(_notesKey, notesJson);
|
||||
|
||||
print('删除笔记成功: $noteId');
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('删除笔记失败: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 切换笔记置顶状态
|
||||
/// [noteId] 笔记ID
|
||||
/// 返回新的置顶状态
|
||||
static Future<bool> togglePinNote(String noteId) async {
|
||||
try {
|
||||
final notes = await getNotes();
|
||||
final index = notes.indexWhere((n) => n['id'] == noteId);
|
||||
|
||||
if (index == -1) {
|
||||
print('未找到笔记: $noteId');
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -695,34 +580,25 @@ class HistoryController {
|
||||
final notesJson = json.encode(notes);
|
||||
await SQLiteStorageController.setString(_notesKey, notesJson);
|
||||
|
||||
print('切换置顶状态: $noteId, 新状态: ${!currentPinned}');
|
||||
return !currentPinned;
|
||||
} catch (e) {
|
||||
print('切换置顶状态失败: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 设置笔记密码
|
||||
/// [noteId] 笔记ID
|
||||
/// [password] 密码(为空则取消锁定)
|
||||
/// 返回是否成功
|
||||
static Future<bool> setNotePassword(String noteId, String? password) async {
|
||||
try {
|
||||
final notes = await getNotes();
|
||||
final index = notes.indexWhere((n) => n['id'] == noteId);
|
||||
|
||||
if (index == -1) {
|
||||
print('未找到笔记: $noteId');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (password == null || password.isEmpty) {
|
||||
// 取消锁定
|
||||
notes[index]['isLocked'] = false;
|
||||
notes[index]['password'] = null;
|
||||
} else {
|
||||
// 设置密码并锁定
|
||||
notes[index]['isLocked'] = true;
|
||||
notes[index]['password'] = password;
|
||||
}
|
||||
@@ -730,20 +606,12 @@ class HistoryController {
|
||||
final notesJson = json.encode(notes);
|
||||
await SQLiteStorageController.setString(_notesKey, notesJson);
|
||||
|
||||
print(
|
||||
'设置笔记密码成功: $noteId, 锁定: ${password != null && password.isNotEmpty}',
|
||||
);
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('设置笔记密码失败: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 验证笔记密码
|
||||
/// [noteId] 笔记ID
|
||||
/// [password] 输入的密码
|
||||
/// 返回是否验证成功
|
||||
static Future<bool> verifyNotePassword(String noteId, String password) async {
|
||||
try {
|
||||
final notes = await getNotes();
|
||||
@@ -753,30 +621,25 @@ class HistoryController {
|
||||
);
|
||||
|
||||
if (note.isEmpty) {
|
||||
print('未找到笔记: $noteId');
|
||||
return false;
|
||||
}
|
||||
|
||||
final storedPassword = note['password'] as String?;
|
||||
if (storedPassword == null || storedPassword.isEmpty) {
|
||||
// 没有密码,直接通过
|
||||
return true;
|
||||
}
|
||||
|
||||
return storedPassword == password;
|
||||
} catch (e) {
|
||||
print('验证笔记密码失败: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取笔记数量
|
||||
static Future<int> getNotesCount() async {
|
||||
try {
|
||||
final notes = await getNotes();
|
||||
return notes.length;
|
||||
} catch (e) {
|
||||
print('获取笔记数量失败: $e');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ class LocalCacheManager {
|
||||
return decoded.cast<Map<String, dynamic>>();
|
||||
}
|
||||
} catch (e) {
|
||||
print('解析缓存数据失败: $e');
|
||||
// 解析失败
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -13,13 +13,8 @@ class SQLiteStorageController {
|
||||
/// 初始化SharedPreferences
|
||||
static Future<void> init() async {
|
||||
try {
|
||||
print('开始初始化SharedPreferences...');
|
||||
|
||||
_prefs = await SharedPreferences.getInstance();
|
||||
|
||||
print('SharedPreferences初始化成功');
|
||||
} catch (e) {
|
||||
print('SharedPreferences初始化失败: $e');
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -37,9 +32,7 @@ class SQLiteStorageController {
|
||||
try {
|
||||
final instance = await _getInstance();
|
||||
await instance.setString(key, value);
|
||||
print('设置字符串值: $key');
|
||||
} catch (e) {
|
||||
print('设置字符串值失败: $e');
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -52,10 +45,8 @@ class SQLiteStorageController {
|
||||
try {
|
||||
final instance = await _getInstance();
|
||||
final value = instance.getString(key) ?? defaultValue;
|
||||
print('获取字符串值: $key = $value');
|
||||
return value;
|
||||
} catch (e) {
|
||||
print('获取字符串值失败: $e');
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
@@ -65,9 +56,7 @@ class SQLiteStorageController {
|
||||
try {
|
||||
final instance = await _getInstance();
|
||||
await instance.setInt(key, value);
|
||||
print('设置整数值: $key = $value');
|
||||
} catch (e) {
|
||||
print('设置整数值失败: $e');
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -77,10 +66,8 @@ class SQLiteStorageController {
|
||||
try {
|
||||
final instance = await _getInstance();
|
||||
final value = instance.getInt(key) ?? defaultValue;
|
||||
print('获取整数值: $key = $value');
|
||||
return value;
|
||||
} catch (e) {
|
||||
print('获取整数值失败: $e');
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
@@ -90,9 +77,7 @@ class SQLiteStorageController {
|
||||
try {
|
||||
final instance = await _getInstance();
|
||||
await instance.setBool(key, value);
|
||||
print('设置布尔值: $key = $value');
|
||||
} catch (e) {
|
||||
print('设置布尔值失败: $e');
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -102,10 +87,8 @@ class SQLiteStorageController {
|
||||
try {
|
||||
final instance = await _getInstance();
|
||||
final value = instance.getBool(key) ?? defaultValue;
|
||||
print('获取布尔值: $key = $value');
|
||||
return value;
|
||||
} catch (e) {
|
||||
print('获取布尔值失败: $e');
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
@@ -115,9 +98,7 @@ class SQLiteStorageController {
|
||||
try {
|
||||
final instance = await _getInstance();
|
||||
await instance.setDouble(key, value);
|
||||
print('设置双精度值: $key = $value');
|
||||
} catch (e) {
|
||||
print('设置双精度值失败: $e');
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -130,10 +111,8 @@ class SQLiteStorageController {
|
||||
try {
|
||||
final instance = await _getInstance();
|
||||
final value = instance.getDouble(key) ?? defaultValue;
|
||||
print('获取双精度值: $key = $value');
|
||||
return value;
|
||||
} catch (e) {
|
||||
print('获取双精度值失败: $e');
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
@@ -143,9 +122,7 @@ class SQLiteStorageController {
|
||||
try {
|
||||
final instance = await _getInstance();
|
||||
await instance.setStringList(key, value);
|
||||
print('设置字符串列表: $key (数量: ${value.length})');
|
||||
} catch (e) {
|
||||
print('设置字符串列表失败: $e');
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -158,10 +135,8 @@ class SQLiteStorageController {
|
||||
try {
|
||||
final instance = await _getInstance();
|
||||
final value = instance.getStringList(key) ?? defaultValue ?? [];
|
||||
print('获取字符串列表: $key (数量: ${value.length})');
|
||||
return value;
|
||||
} catch (e) {
|
||||
print('获取字符串列表失败: $e');
|
||||
return defaultValue ?? [];
|
||||
}
|
||||
}
|
||||
@@ -171,9 +146,7 @@ class SQLiteStorageController {
|
||||
try {
|
||||
final instance = await _getInstance();
|
||||
await instance.remove(key);
|
||||
print('移除存储值: $key');
|
||||
} catch (e) {
|
||||
print('移除存储值失败: $e');
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -183,9 +156,7 @@ class SQLiteStorageController {
|
||||
try {
|
||||
final instance = await _getInstance();
|
||||
await instance.clear();
|
||||
print('清空所有存储');
|
||||
} catch (e) {
|
||||
print('清空存储失败: $e');
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -195,10 +166,8 @@ class SQLiteStorageController {
|
||||
try {
|
||||
final instance = await _getInstance();
|
||||
final keys = instance.getKeys();
|
||||
print('获取存储键: ${keys.length}个');
|
||||
return keys;
|
||||
} catch (e) {
|
||||
print('获取存储键失败: $e');
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@@ -208,10 +177,8 @@ class SQLiteStorageController {
|
||||
try {
|
||||
final instance = await _getInstance();
|
||||
final exists = instance.containsKey(key);
|
||||
print('检查键存在: $key = $exists');
|
||||
return exists;
|
||||
} catch (e) {
|
||||
print('检查键存在失败: $e');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -221,9 +188,8 @@ class SQLiteStorageController {
|
||||
try {
|
||||
final instance = await _getInstance();
|
||||
await instance.reload();
|
||||
print('重新加载存储数据');
|
||||
} catch (e) {
|
||||
print('重新加载数据失败: $e');
|
||||
// 忽略错误
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,46 +69,30 @@ class NetworkListenerService {
|
||||
void startLoading(String key) {
|
||||
_loadingStates[key] = true;
|
||||
_updateStatus(NetworkStatus.loading);
|
||||
|
||||
if (kDebugMode) {
|
||||
print('NetworkListener: 开始加载 - $key');
|
||||
}
|
||||
}
|
||||
|
||||
/// 结束网络操作
|
||||
void endLoading(String key) {
|
||||
_loadingStates.remove(key);
|
||||
|
||||
|
||||
if (_loadingStates.isEmpty) {
|
||||
_updateStatus(NetworkStatus.idle);
|
||||
}
|
||||
|
||||
if (kDebugMode) {
|
||||
print('NetworkListener: 结束加载 - $key');
|
||||
}
|
||||
}
|
||||
|
||||
/// 发送成功事件
|
||||
void sendSuccessEvent(NetworkEventType type, {String? data}) {
|
||||
_updateStatus(NetworkStatus.success);
|
||||
_eventController.add(NetworkEvent(type: type, data: data));
|
||||
|
||||
if (kDebugMode) {
|
||||
print('NetworkListener: 成功事件 - $type, 数据: $data');
|
||||
}
|
||||
}
|
||||
|
||||
/// 发送错误事件
|
||||
void sendErrorEvent(NetworkEventType type, {String? errorMessage}) {
|
||||
_updateStatus(NetworkStatus.error);
|
||||
_eventController.add(NetworkEvent(
|
||||
type: type,
|
||||
type: type,
|
||||
errorMessage: errorMessage,
|
||||
));
|
||||
|
||||
if (kDebugMode) {
|
||||
print('NetworkListener: 错误事件 - $type, 错误: $errorMessage');
|
||||
}
|
||||
}
|
||||
|
||||
/// 发送点赞事件
|
||||
@@ -132,10 +116,6 @@ class NetworkListenerService {
|
||||
if (_status != newStatus) {
|
||||
_status = newStatus;
|
||||
_statusController.add(_status);
|
||||
|
||||
if (kDebugMode) {
|
||||
print('NetworkListener: 状态更新 - $newStatus');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
import 'package:audioplayers/audioplayers.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
/// 时间: 2026-03-30
|
||||
/// 功能: 音频管理类
|
||||
/// 介绍: 管理应用中的音效播放,包括点击音效、点赞音效等
|
||||
/// 最新变化: 新增音频播放功能
|
||||
/// 最新变化: 使用最简单的音频播放方式
|
||||
|
||||
class AudioManager {
|
||||
static AudioManager? _instance;
|
||||
late AudioPlayer _audioPlayer;
|
||||
bool _isInitialized = false;
|
||||
bool _isMuted = false;
|
||||
|
||||
AudioManager._internal() {
|
||||
_audioPlayer = AudioPlayer();
|
||||
}
|
||||
AudioManager._internal();
|
||||
|
||||
factory AudioManager() {
|
||||
_instance ??= AudioManager._internal();
|
||||
@@ -25,73 +23,64 @@ class AudioManager {
|
||||
if (_isInitialized) return;
|
||||
|
||||
try {
|
||||
// 设置音频播放器模式
|
||||
await _audioPlayer.setPlayerMode(PlayerMode.lowLatency);
|
||||
await _loadSoundSetting();
|
||||
_isInitialized = true;
|
||||
_debugLog('音频管理器初始化成功');
|
||||
} catch (e) {
|
||||
_debugLog('音频管理器初始化失败: $e');
|
||||
// 初始化失败
|
||||
}
|
||||
}
|
||||
|
||||
/// 加载保存的声音设置
|
||||
Future<void> _loadSoundSetting() async {
|
||||
try {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
bool soundEnabled = prefs.getBool('sound_enabled') ?? false;
|
||||
_isMuted = !soundEnabled;
|
||||
} catch (e) {
|
||||
// 加载设置失败
|
||||
}
|
||||
}
|
||||
|
||||
/// 播放点击音效
|
||||
Future<void> playClickSound() async {
|
||||
if (_isMuted) return;
|
||||
await _playSound('audios/deep.mp3');
|
||||
void playClickSound() {
|
||||
_playSound('audios/deep.mp3');
|
||||
}
|
||||
|
||||
/// 播放点赞音效
|
||||
Future<void> playLikeSound() async {
|
||||
if (_isMuted) return;
|
||||
await _playSound('audios/deep.mp3');
|
||||
void playLikeSound() {
|
||||
_playSound('audios/deep.mp3');
|
||||
}
|
||||
|
||||
/// 播放下一条音效
|
||||
Future<void> playNextSound() async {
|
||||
if (_isMuted) return;
|
||||
await _playSound('audios/deep.mp3');
|
||||
void playNextSound() {
|
||||
_playSound('audios/deep.mp3');
|
||||
}
|
||||
|
||||
/// 通用播放方法
|
||||
Future<void> _playSound(String assetPath) async {
|
||||
if (!_isInitialized) {
|
||||
await init();
|
||||
}
|
||||
/// 播放音频
|
||||
void _playSound(String assetPath) {
|
||||
if (_isMuted) return;
|
||||
_playSoundAsync(assetPath);
|
||||
}
|
||||
|
||||
/// 异步播放音频
|
||||
void _playSoundAsync(String assetPath) async {
|
||||
try {
|
||||
// 停止当前播放的音频
|
||||
await _audioPlayer.stop();
|
||||
// 播放新音频
|
||||
await _audioPlayer.play(AssetSource(assetPath));
|
||||
_debugLog('播放音效: $assetPath');
|
||||
final player = AudioPlayer();
|
||||
await player.play(AssetSource(assetPath));
|
||||
|
||||
player.onPlayerComplete.listen((_) {
|
||||
player.dispose();
|
||||
});
|
||||
} catch (e) {
|
||||
_debugLog('播放音效失败: $e');
|
||||
// 播放失败
|
||||
}
|
||||
}
|
||||
|
||||
/// 设置静音状态
|
||||
void setMuted(bool muted) {
|
||||
_isMuted = muted;
|
||||
_debugLog('静音状态: $_isMuted');
|
||||
}
|
||||
|
||||
/// 获取静音状态
|
||||
bool get isMuted => _isMuted;
|
||||
|
||||
/// 释放资源
|
||||
Future<void> dispose() async {
|
||||
try {
|
||||
await _audioPlayer.dispose();
|
||||
_isInitialized = false;
|
||||
_debugLog('音频管理器已释放');
|
||||
} catch (e) {
|
||||
_debugLog('释放音频管理器失败: $e');
|
||||
}
|
||||
}
|
||||
|
||||
void _debugLog(String message) {
|
||||
if (kDebugMode) {
|
||||
print('[AudioManager] $message');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,13 +26,6 @@ class HttpClient {
|
||||
|
||||
static final Dio _dio = Dio(_options);
|
||||
|
||||
/// 添加调试日志
|
||||
static void _debugLog(String message) {
|
||||
if (kDebugMode) {
|
||||
print('HttpClient: $message');
|
||||
}
|
||||
}
|
||||
|
||||
/// GET请求
|
||||
static Future<HttpResponse> get(
|
||||
String path, {
|
||||
@@ -92,10 +85,6 @@ class HttpClient {
|
||||
}) async {
|
||||
try {
|
||||
final url = '$_baseUrl$path';
|
||||
_debugLog('请求 $method $url');
|
||||
if (queryParameters != null) {
|
||||
_debugLog('查询参数: $queryParameters');
|
||||
}
|
||||
|
||||
final options = Options(
|
||||
method: method,
|
||||
@@ -129,9 +118,6 @@ class HttpClient {
|
||||
throw UnsupportedError('HTTP method $method is not supported');
|
||||
}
|
||||
|
||||
_debugLog('响应状态: ${response.statusCode}');
|
||||
_debugLog('响应数据: ${response.data}');
|
||||
|
||||
return HttpResponse(
|
||||
statusCode: response.statusCode ?? 0,
|
||||
body: response.data is String
|
||||
@@ -140,7 +126,6 @@ class HttpClient {
|
||||
headers: response.headers.map.cast<String, String>(),
|
||||
);
|
||||
} on DioException catch (e) {
|
||||
_debugLog('Dio异常: ${e.type} - ${e.message}');
|
||||
String message;
|
||||
switch (e.type) {
|
||||
case DioExceptionType.connectionTimeout:
|
||||
@@ -159,7 +144,6 @@ class HttpClient {
|
||||
}
|
||||
throw HttpException(message);
|
||||
} catch (e) {
|
||||
_debugLog('未知异常: $e');
|
||||
throw HttpException('请求失败:$e');
|
||||
}
|
||||
}
|
||||
@@ -175,13 +159,6 @@ class HttpClient {
|
||||
}) async {
|
||||
try {
|
||||
final url = '$_baseUrl$path';
|
||||
_debugLog('FormData请求 $method $url');
|
||||
if (queryParameters != null) {
|
||||
_debugLog('查询参数: $queryParameters');
|
||||
}
|
||||
if (data != null) {
|
||||
_debugLog('表单数据: $data');
|
||||
}
|
||||
|
||||
final formData = FormData.fromMap(data ?? {});
|
||||
|
||||
@@ -213,9 +190,6 @@ class HttpClient {
|
||||
throw UnsupportedError('FormData only supports POST method');
|
||||
}
|
||||
|
||||
_debugLog('响应状态: ${response.statusCode}');
|
||||
_debugLog('响应数据: ${response.data}');
|
||||
|
||||
return HttpResponse(
|
||||
statusCode: response.statusCode ?? 0,
|
||||
body: response.data is String
|
||||
@@ -224,7 +198,6 @@ class HttpClient {
|
||||
headers: response.headers.map.cast<String, String>(),
|
||||
);
|
||||
} on DioException catch (e) {
|
||||
_debugLog('Dio异常: ${e.type} - ${e.message}');
|
||||
String message;
|
||||
switch (e.type) {
|
||||
case DioExceptionType.connectionTimeout:
|
||||
@@ -243,7 +216,6 @@ class HttpClient {
|
||||
}
|
||||
throw HttpException(message);
|
||||
} catch (e) {
|
||||
_debugLog('未知异常: $e');
|
||||
throw HttpException('请求失败:$e');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,11 +269,6 @@ class PoetryData {
|
||||
});
|
||||
|
||||
factory PoetryData.fromJson(Map<String, dynamic> json) {
|
||||
// 添加调试信息
|
||||
if (kDebugMode) {
|
||||
print('PoetryData.fromJson: 输入JSON = $json');
|
||||
}
|
||||
|
||||
try {
|
||||
final poetryData = PoetryData(
|
||||
id: int.tryParse(json['id'].toString()) ?? 0,
|
||||
@@ -295,16 +290,9 @@ class PoetryData {
|
||||
createTime: json['create_time']?.toString() ?? '',
|
||||
updateTime: json['update_time']?.toString() ?? '',
|
||||
);
|
||||
|
||||
if (kDebugMode) {
|
||||
print('PoetryData.fromJson: 解析成功');
|
||||
}
|
||||
|
||||
|
||||
return poetryData;
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print('PoetryData.fromJson: 解析失败 - $e');
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,32 +34,19 @@ class VoteApi {
|
||||
static final Dio _dio = Dio(_options)
|
||||
..interceptors.add(CookieManager(_cookieJar));
|
||||
|
||||
static void _debugLog(String message) {
|
||||
if (kDebugMode) {
|
||||
print('VoteApi: $message');
|
||||
}
|
||||
}
|
||||
|
||||
static Future<Map<String, dynamic>> _get(
|
||||
String path, {
|
||||
Map<String, dynamic>? queryParameters,
|
||||
}) async {
|
||||
try {
|
||||
final url = '$_baseUrl$path';
|
||||
_debugLog('GET $url');
|
||||
if (queryParameters != null) {
|
||||
_debugLog('查询参数: $queryParameters');
|
||||
}
|
||||
|
||||
final response = await _dio.get(url, queryParameters: queryParameters);
|
||||
|
||||
_debugLog('响应: ${response.data}');
|
||||
return response.data as Map<String, dynamic>;
|
||||
} on DioException catch (e) {
|
||||
_debugLog('Dio异常: ${e.type} - ${e.message}');
|
||||
throw Exception('请求失败: ${e.message}');
|
||||
} catch (e) {
|
||||
_debugLog('未知异常: $e');
|
||||
throw Exception('请求失败: $e');
|
||||
}
|
||||
}
|
||||
@@ -70,20 +57,13 @@ class VoteApi {
|
||||
}) async {
|
||||
try {
|
||||
final url = '$_baseUrl$path';
|
||||
_debugLog('POST $url');
|
||||
if (data != null) {
|
||||
_debugLog('请求数据: $data');
|
||||
}
|
||||
|
||||
final response = await _dio.post(url, data: data);
|
||||
|
||||
_debugLog('响应: ${response.data}');
|
||||
return response.data as Map<String, dynamic>;
|
||||
} on DioException catch (e) {
|
||||
_debugLog('Dio异常: ${e.type} - ${e.message}');
|
||||
throw Exception('请求失败: ${e.message}');
|
||||
} catch (e) {
|
||||
_debugLog('未知异常: $e');
|
||||
throw Exception('请求失败: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,10 +337,8 @@ class _PopularPageState extends State<PopularPage>
|
||||
final isPreloadEnabled = await LocalCacheManager().isPreloadEnabled();
|
||||
|
||||
if (isPreloadEnabled && !forceRefresh) {
|
||||
print('预加载模式:尝试从本地缓存加载数据');
|
||||
final cachedData = await LocalCacheManager().getCachedPopularList(type);
|
||||
if (cachedData != null && cachedData.isNotEmpty) {
|
||||
print('从本地缓存加载数据成功');
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_rankList = cachedData
|
||||
@@ -351,29 +349,19 @@ class _PopularPageState extends State<PopularPage>
|
||||
}
|
||||
return;
|
||||
}
|
||||
print('本地缓存为空,从服务器加载');
|
||||
}
|
||||
|
||||
print('正在请求排行榜数据: type=$type, period=$type');
|
||||
|
||||
final response = await HttpClient.get(
|
||||
'/rlist.php',
|
||||
queryParameters: {'type': type, 'limit': '20'},
|
||||
);
|
||||
|
||||
print('API响应状态: ${response.statusCode}');
|
||||
print('API响应成功: ${response.isSuccess}');
|
||||
print('API响应代码: ${response.code}');
|
||||
print('API响应消息: ${response.message}');
|
||||
print('API响应数据: ${response.data}');
|
||||
|
||||
if (response.isSuccess && response.code == 0) {
|
||||
final data = response.data;
|
||||
final rankData = data['list'] as List<dynamic>? ?? [];
|
||||
final rankDataList = rankData.cast<Map<String, dynamic>>();
|
||||
|
||||
if (isPreloadEnabled) {
|
||||
print('保存数据到本地缓存');
|
||||
await LocalCacheManager().cachePopularList(type, rankDataList);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ class _CollectNotesPageState extends State<CollectNotesPage> {
|
||||
_category = note['category'] ?? _categoryOptions[0];
|
||||
}
|
||||
} catch (e) {
|
||||
print('加载笔记失败: $e');
|
||||
// 加载失败
|
||||
}
|
||||
|
||||
setState(() {
|
||||
@@ -150,14 +150,13 @@ class _CollectNotesPageState extends State<CollectNotesPage> {
|
||||
_createTime = _lastSavedTime;
|
||||
}
|
||||
setState(() {});
|
||||
print('笔记已自动保存');
|
||||
NetworkListenerService().sendSuccessEvent(
|
||||
NetworkEventType.noteUpdate,
|
||||
data: noteId,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
print('保存笔记失败: $e');
|
||||
// 保存失败
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -93,11 +93,8 @@ class _FootprintPageState extends State<FootprintPage>
|
||||
|
||||
Future<void> _showPoetryDetails(PoetryData poetry) async {
|
||||
try {
|
||||
print('DEBUG: 点击查看详情 - Poetry ID: ${poetry.id}');
|
||||
|
||||
// 从SQLite获取完整数据
|
||||
final likedList = await HistoryController.getLikedHistory();
|
||||
print('DEBUG: 获取到 ${likedList.length} 条点赞记录');
|
||||
|
||||
// 查找对应的诗词数据,优先使用存储的完整数据
|
||||
Map<String, dynamic> poetryData;
|
||||
@@ -106,14 +103,10 @@ class _FootprintPageState extends State<FootprintPage>
|
||||
(item) => item['id'].toString() == poetry.id.toString(),
|
||||
orElse: () => poetry.toJson(),
|
||||
);
|
||||
print('DEBUG: 找到匹配的诗词数据');
|
||||
} catch (e) {
|
||||
print('DEBUG: 未找到匹配数据,使用当前poetry数据');
|
||||
poetryData = poetry.toJson();
|
||||
}
|
||||
|
||||
print('DEBUG: 诗词数据字段: ${poetryData.keys.toList()}');
|
||||
|
||||
if (mounted) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
@@ -301,7 +294,6 @@ class _FootprintPageState extends State<FootprintPage>
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
print('DEBUG: 显示详情失败 - $e');
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
@@ -666,7 +658,6 @@ class _FootprintPageState extends State<FootprintPage>
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () {
|
||||
print('DEBUG: 查看详情按钮被点击 - Poetry ID: ${poetry.id}');
|
||||
_showPoetryDetails(poetry);
|
||||
},
|
||||
icon: const Icon(Icons.visibility, size: 18),
|
||||
|
||||
@@ -62,7 +62,6 @@ class _LocalNotesListState extends State<LocalNotesList> {
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
print('加载笔记失败: $e');
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isLoadingNotes = false;
|
||||
@@ -528,7 +527,7 @@ class _LocalNotesListState extends State<LocalNotesList> {
|
||||
).showSnackBar(const SnackBar(content: Text('已更新置顶状态')));
|
||||
}
|
||||
} catch (e) {
|
||||
print('切换置顶失败: $e');
|
||||
// 切换失败
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ class AutoRefreshManager {
|
||||
Future<void> init() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
_isEnabled = prefs.getBool(_autoRefreshKey) ?? false;
|
||||
_debugLog('自动刷新初始化,状态: $_isEnabled');
|
||||
}
|
||||
|
||||
bool get isEnabled => _isEnabled;
|
||||
@@ -37,7 +36,6 @@ class AutoRefreshManager {
|
||||
_isEnabled = enabled;
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setBool(_autoRefreshKey, enabled);
|
||||
_debugLog('自动刷新状态已设置: $enabled');
|
||||
|
||||
if (enabled) {
|
||||
_startTimer();
|
||||
@@ -48,25 +46,21 @@ class AutoRefreshManager {
|
||||
|
||||
void setOnRefresh(VoidCallback? callback) {
|
||||
_onRefresh = callback;
|
||||
_debugLog('设置刷新回调');
|
||||
}
|
||||
|
||||
void _startTimer() {
|
||||
_stopTimer();
|
||||
_refreshTimer = Timer.periodic(_refreshInterval, (timer) {
|
||||
_debugLog('自动刷新触发');
|
||||
if (_onRefresh != null) {
|
||||
_onRefresh!();
|
||||
}
|
||||
});
|
||||
_debugLog('自动刷新定时器已启动');
|
||||
}
|
||||
|
||||
void _stopTimer() {
|
||||
if (_refreshTimer != null) {
|
||||
_refreshTimer!.cancel();
|
||||
_refreshTimer = null;
|
||||
_debugLog('自动刷新定时器已停止');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,11 +71,6 @@ class AutoRefreshManager {
|
||||
void dispose() {
|
||||
_stopTimer();
|
||||
_onRefresh = null;
|
||||
_debugLog('自动刷新管理器已释放');
|
||||
}
|
||||
|
||||
void _debugLog(String message) {
|
||||
if (kDebugMode) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +92,6 @@ class DebugInfoManager {
|
||||
Future<void> init() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
_isEnabled = prefs.getBool(_debugInfoKey) ?? false;
|
||||
_debugLog('调试信息初始化,状态: $_isEnabled');
|
||||
}
|
||||
|
||||
bool get isEnabled => _isEnabled;
|
||||
@@ -113,7 +101,6 @@ class DebugInfoManager {
|
||||
_isEnabled = enabled;
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setBool(_debugInfoKey, enabled);
|
||||
_debugLog('调试信息状态已设置: $enabled');
|
||||
|
||||
if (!enabled) {
|
||||
_messageNotifier.value = '';
|
||||
@@ -124,12 +111,10 @@ class DebugInfoManager {
|
||||
if (!_isEnabled) return;
|
||||
|
||||
_messageNotifier.value = message;
|
||||
_debugLog('显示调试信息: $message');
|
||||
|
||||
_messageTimer?.cancel();
|
||||
_messageTimer = Timer(const Duration(seconds: 2), () {
|
||||
_messageNotifier.value = '';
|
||||
_debugLog('调试信息已隐藏');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -176,11 +161,6 @@ class DebugInfoManager {
|
||||
void dispose() {
|
||||
_messageTimer?.cancel();
|
||||
_messageNotifier.value = '';
|
||||
_debugLog('调试信息管理器已清理');
|
||||
}
|
||||
|
||||
void _debugLog(String message) {
|
||||
if (kDebugMode) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +181,6 @@ class OfflineDataManager {
|
||||
|
||||
Future<void> init() async {
|
||||
await _loadCachedData();
|
||||
_debugLog('离线数据管理器初始化,缓存数量: ${_cachedPoetryList.length}');
|
||||
}
|
||||
|
||||
Future<bool> isOnline() async {
|
||||
@@ -273,7 +252,7 @@ class OfflineDataManager {
|
||||
|
||||
_cachedPoetryList.add(map);
|
||||
} catch (e) {
|
||||
_debugLog('解析缓存数据失败: $e');
|
||||
// 解析失败
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -320,12 +299,7 @@ class OfflineDataManager {
|
||||
updateTime: updateTime,
|
||||
);
|
||||
} catch (e) {
|
||||
_debugLog('转换为PoetryData失败: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void _debugLog(String message) {
|
||||
if (kDebugMode) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,8 +293,8 @@ class _HomePageState extends State<HomePage>
|
||||
Future<void> _toggleLike() async {
|
||||
if (_poetryData == null || _isLoadingLike) return;
|
||||
|
||||
// 播放点赞音效
|
||||
await AudioManager().playLikeSound();
|
||||
// 播放点赞音效(不等待完成)
|
||||
AudioManager().playLikeSound();
|
||||
|
||||
// 立即切换按钮状态和显示加载
|
||||
setState(() {
|
||||
@@ -397,7 +397,7 @@ class _HomePageState extends State<HomePage>
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
print('加载历史记录失败: $e');
|
||||
// 加载失败
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,7 +413,7 @@ class _HomePageState extends State<HomePage>
|
||||
|
||||
await HistoryController.addToHistory(poetryMap);
|
||||
} catch (e) {
|
||||
print('保存历史记录失败: $e');
|
||||
// 保存失败
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,8 +434,8 @@ class _HomePageState extends State<HomePage>
|
||||
void _loadNextPoetry() async {
|
||||
if (_isLoadingNext) return;
|
||||
|
||||
// 播放下一条音效
|
||||
await AudioManager().playNextSound();
|
||||
// 播放下一条音效(不等待完成)
|
||||
AudioManager().playNextSound();
|
||||
|
||||
setState(() {
|
||||
_isLoadingNext = true;
|
||||
|
||||
@@ -106,9 +106,9 @@ class _PoetryCardState extends State<PoetryCard> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
// 播放点击音效
|
||||
await AudioManager().playClickSound();
|
||||
onTap: () {
|
||||
// 播放点击音效(不等待完成)
|
||||
AudioManager().playClickSound();
|
||||
// 调用原始的onTap回调
|
||||
widget.onTap?.call();
|
||||
},
|
||||
@@ -715,6 +715,7 @@ class FloatingPreviousButton extends StatelessWidget {
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
onTap: () {
|
||||
HapticFeedback.lightImpact();
|
||||
AudioManager().playClickSound();
|
||||
onPrevious();
|
||||
},
|
||||
child: const Center(
|
||||
@@ -755,6 +756,7 @@ class FloatingNextButton extends StatelessWidget {
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
onTap: () {
|
||||
HapticFeedback.lightImpact();
|
||||
AudioManager().playNextSound();
|
||||
onNext();
|
||||
},
|
||||
child: const Center(
|
||||
@@ -805,6 +807,7 @@ class FloatingLikeButton extends StatelessWidget {
|
||||
? null
|
||||
: () {
|
||||
HapticFeedback.mediumImpact();
|
||||
AudioManager().playLikeSound();
|
||||
onToggleLike();
|
||||
},
|
||||
child: Center(
|
||||
|
||||
@@ -20,63 +20,160 @@ class _BugListPageState extends State<BugListPage> {
|
||||
final List<Map<String, dynamic>> _bugs = [
|
||||
{
|
||||
'id': 1,
|
||||
'title': '诗词答题页面偶现卡顿',
|
||||
'description': '在快速切换诗词题目时,页面可能出现短暂卡顿现象',
|
||||
'title': '输入法无法弹出',
|
||||
'description': '输入框无焦点,输入法无法弹出',
|
||||
'severity': 'medium', // high, medium, low
|
||||
'status': 'pending', // pending, in_progress, resolved
|
||||
'solution': '优化页面渲染逻辑,减少不必要的widget重建',
|
||||
'resolveTime': '2026-04-15',
|
||||
'solution': '1.重启手机',
|
||||
'reproduction': '1. 打开系统设置 - 存储 清理缓存\n2. 打开软件poes输入框页面\n*仅极少部分鸿蒙用户触发此现象',
|
||||
'resolveTime': '修复中',
|
||||
'reportTime': '2026-03-25',
|
||||
'affectedUsers': '部分用户',
|
||||
'expanded': false, // 添加展开状态
|
||||
'affectedUsers': '鸿蒙5/6用户',
|
||||
'expanded': false, // 解决方案展开状态
|
||||
'reproductionExpanded': false, // 复现步骤展开状态
|
||||
},
|
||||
{
|
||||
'id': 2,
|
||||
'title': '历史记录加载缓慢',
|
||||
'description': '当历史记录数量较多时,加载速度较慢',
|
||||
'title': '软件页面刷新率只有60帧',
|
||||
'description': '软件外120帧,打开软件后,刷新率只有60帧',
|
||||
'severity': 'high',
|
||||
'status': 'in_progress',
|
||||
'solution': '实现分页加载和本地缓存优化',
|
||||
'status': 'resolved',
|
||||
'solution': '新版已修复',
|
||||
'reproduction': '1. 极少鸿蒙用户仍会出现刷新率只有60帧,无原生刷新率',
|
||||
'resolveTime': '2026-04-10',
|
||||
'reportTime': '2026-03-20',
|
||||
'affectedUsers': '大量用户',
|
||||
'expanded': false, // 添加展开状态
|
||||
'affectedUsers': '鸿蒙5/6用户',
|
||||
'expanded': false, // 解决方案展开状态
|
||||
'reproductionExpanded': false, // 复现步骤展开状态
|
||||
},
|
||||
{
|
||||
'id': 3,
|
||||
'title': '主题切换不生效',
|
||||
'description': '在某些设备上切换主题后,界面颜色没有立即更新',
|
||||
'title': '应用信息 设备类型显示 未知',
|
||||
'description': '已适配安卓 win web系统',
|
||||
'severity': 'low',
|
||||
'status': 'resolved',
|
||||
'solution': '修复主题状态管理问题,强制刷新界面',
|
||||
'resolveTime': '2026-03-28',
|
||||
'solution': '部分web ohos系统未识别到系统类型',
|
||||
'reproduction':
|
||||
'harmonyos系统检测字段为\n ohos,openharmony,harmony\n 不在字段中的设备无法识别',
|
||||
'resolveTime': '修复中',
|
||||
'reportTime': '2026-03-15',
|
||||
'affectedUsers': '少数用户',
|
||||
'expanded': false, // 添加展开状态
|
||||
'expanded': false, // 解决方案展开状态
|
||||
'reproductionExpanded': false, // 复现步骤展开状态
|
||||
},
|
||||
{
|
||||
'id': 4,
|
||||
'title': '收藏夹同步失败',
|
||||
'description': '网络不稳定时,收藏夹数据同步可能失败',
|
||||
'title': '软件横屏后,部分页面无法点击',
|
||||
'description': '暂未适配横屏',
|
||||
'severity': 'medium',
|
||||
'status': 'pending',
|
||||
'solution': '增加重试机制和离线缓存功能',
|
||||
'resolveTime': '2026-04-20',
|
||||
'reproduction': '1. 开启屏幕旋转,手机横屏',
|
||||
'resolveTime': '适配中',
|
||||
'reportTime': '2026-03-22',
|
||||
'affectedUsers': '部分用户',
|
||||
'expanded': false, // 添加展开状态
|
||||
'affectedUsers': '大部分用户',
|
||||
'expanded': false, // 解决方案展开状态
|
||||
'reproductionExpanded': false, // 复现步骤展开状态
|
||||
},
|
||||
{
|
||||
'id': 5,
|
||||
'title': '字体大小设置异常',
|
||||
'description': '调整字体大小后,部分页面文字显示不完整',
|
||||
'title': '笔记页面时间显示1970xxx',
|
||||
'description': '在其他页面点击创建添加笔记,笔记时间显示异常',
|
||||
'severity': 'low',
|
||||
'status': 'resolved',
|
||||
'solution': '优化字体大小适配逻辑,确保所有页面正确显示',
|
||||
'reproduction': '1. 进入设置页面\n2. 调整字体大小为最大值\n3. 浏览各个页面,观察文字是否显示完整',
|
||||
'resolveTime': '2026-03-26',
|
||||
'reportTime': '2026-03-18',
|
||||
'affectedUsers': '少数用户',
|
||||
'expanded': false, // 添加展开状态
|
||||
'expanded': false, // 解决方案展开状态
|
||||
'reproductionExpanded': false, // 复现步骤展开状态
|
||||
},
|
||||
{
|
||||
'id': 6,
|
||||
'title': '离线状态错误',
|
||||
'description': '断网或网络异常,软件内未正确获取到',
|
||||
'severity': 'low',
|
||||
'status': 'resolved',
|
||||
'solution': '优化字体大小适配逻辑,确保所有页面正确显示',
|
||||
'reproduction': '1. 用户关闭在线状态,软件部分页面显示',
|
||||
'resolveTime': '2026-03-26',
|
||||
'reportTime': '2026-03-18',
|
||||
'affectedUsers': '少数用户',
|
||||
'expanded': false, // 解决方案展开状态
|
||||
'reproductionExpanded': false, // 复现步骤展开状态
|
||||
},
|
||||
{
|
||||
'id': 7,
|
||||
'title': '主页点击“上一条” 显示无上一条',
|
||||
'description': '未读取到历史记录',
|
||||
'severity': 'low',
|
||||
'status': 'resolved',
|
||||
'solution': '优化字体大小适配逻辑,确保所有页面正确显示',
|
||||
'reproduction': '1. 用户关闭在线状态,软件部分页面显示',
|
||||
'resolveTime': '2026-03-26',
|
||||
'reportTime': '2026-03-18',
|
||||
'affectedUsers': '全部用户',
|
||||
'expanded': false, // 解决方案展开状态
|
||||
'reproductionExpanded': false, // 复现步骤展开状态
|
||||
},
|
||||
{
|
||||
'id': 8,
|
||||
'title': '软件冷启动出现长时间白屏',
|
||||
'description': '未读取到历史记录',
|
||||
'severity': 'low',
|
||||
'status': 'resolved',
|
||||
'solution': '闪白屏',
|
||||
'reproduction': '首次按钮,系统设置页面清理poes数据 大版本更新',
|
||||
'resolveTime': '2026-03-26',
|
||||
'reportTime': '2026-03-18',
|
||||
'affectedUsers': '少数用户',
|
||||
'expanded': false, // 解决方案展开状态
|
||||
'reproductionExpanded': false, // 复现步骤展开状态
|
||||
},
|
||||
|
||||
{
|
||||
'id': 8,
|
||||
'title': '软件黑屏',
|
||||
'description': '未读取到历史记录',
|
||||
'severity': 'low',
|
||||
'status': 'resolved',
|
||||
'solution': '优化字体大小适配逻辑,确保所有页面正确显示',
|
||||
'reproduction': '极短时间内瞬发点击同一个按钮3次以上 页面路由加载异常',
|
||||
'resolveTime': '2026-03-26',
|
||||
'reportTime': '2026-03-18',
|
||||
'affectedUsers': '少数用户',
|
||||
'expanded': false, // 解决方案展开状态
|
||||
'reproductionExpanded': false, // 复现步骤展开状态
|
||||
},
|
||||
|
||||
{
|
||||
'id': 9,
|
||||
'title': '桌面卡片 天气温度显示999',
|
||||
'description': '未读取到历史记录',
|
||||
'severity': 'low',
|
||||
'status': 'resolved',
|
||||
'solution': '用户短时间内多次刷新获取api数据,导致服务器启动防止cc自我保护机制,不会此ip下放数据',
|
||||
'reproduction': '极短时间内瞬发点击同一个按钮3次以上 页面路由加载异常',
|
||||
'resolveTime': '2026-03-26',
|
||||
'reportTime': '2026-03-18',
|
||||
'affectedUsers': '少数用户',
|
||||
'expanded': false, // 解决方案展开状态
|
||||
'reproductionExpanded': false, // 复现步骤展开状态
|
||||
},
|
||||
{
|
||||
'id': 9,
|
||||
'title': '桌面卡片 设置页面闪白屏',
|
||||
'description': '未读取到历史记录',
|
||||
'severity': 'low',
|
||||
'status': 'resolved',
|
||||
'solution': '用户短时间内多次刷新获取api数据,导致服务器启动防止cc自我保护机制,不会此ip下放数据',
|
||||
'reproduction': '极短时间内瞬发点击同一个按钮3次以上 页面路由加载异常',
|
||||
'resolveTime': '2026-03-26',
|
||||
'reportTime': '2026-03-18',
|
||||
'affectedUsers': '少数用户',
|
||||
'expanded': false, // 解决方案展开状态
|
||||
'reproductionExpanded': false, // 复现步骤展开状态
|
||||
},
|
||||
];
|
||||
|
||||
@@ -94,6 +191,18 @@ class _BugListPageState extends State<BugListPage> {
|
||||
HapticFeedback.lightImpact();
|
||||
}
|
||||
|
||||
// 切换复现步骤展开状态
|
||||
void _toggleReproductionExpanded(int bugId) {
|
||||
setState(() {
|
||||
final bugIndex = _bugs.indexWhere((bug) => bug['id'] == bugId);
|
||||
if (bugIndex != -1) {
|
||||
_bugs[bugIndex]['reproductionExpanded'] =
|
||||
!_bugs[bugIndex]['reproductionExpanded'];
|
||||
}
|
||||
});
|
||||
HapticFeedback.lightImpact();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scrollController.dispose();
|
||||
@@ -156,14 +265,14 @@ class _BugListPageState extends State<BugListPage> {
|
||||
setState(() {
|
||||
_isRefreshing = true;
|
||||
});
|
||||
|
||||
|
||||
// 模拟网络请求延迟
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
|
||||
|
||||
setState(() {
|
||||
_isRefreshing = false;
|
||||
});
|
||||
|
||||
|
||||
HapticFeedback.lightImpact();
|
||||
}
|
||||
|
||||
@@ -248,7 +357,7 @@ class _BugListPageState extends State<BugListPage> {
|
||||
|
||||
Widget _buildBugItem(Map<String, dynamic> bug) {
|
||||
final bool isExpanded = bug['expanded'] ?? false;
|
||||
|
||||
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 16),
|
||||
decoration: BoxDecoration(
|
||||
@@ -293,7 +402,9 @@ class _BugListPageState extends State<BugListPage> {
|
||||
vertical: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: _getStatusColor(bug['status']).withValues(alpha: 0.1),
|
||||
color: _getStatusColor(
|
||||
bug['status'],
|
||||
).withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: _getStatusColor(bug['status']),
|
||||
@@ -331,7 +442,9 @@ class _BugListPageState extends State<BugListPage> {
|
||||
vertical: 2,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: _getSeverityColor(bug['severity']).withValues(alpha: 0.1),
|
||||
color: _getSeverityColor(
|
||||
bug['severity'],
|
||||
).withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Row(
|
||||
@@ -355,48 +468,79 @@ class _BugListPageState extends State<BugListPage> {
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Icon(
|
||||
Icons.people,
|
||||
size: 14,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
Icon(Icons.people, size: 14, color: Colors.grey[600]),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
bug['affectedUsers'] ?? '未知用户',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
// 解决方案按钮
|
||||
Container(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => _toggleBugExpanded(bug['id']),
|
||||
icon: Icon(
|
||||
isExpanded ? Icons.expand_less : Icons.expand_more,
|
||||
size: 18,
|
||||
),
|
||||
label: Text(
|
||||
isExpanded ? '收起解决方案' : '查看解决方案',
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppConstants.primaryColor.withValues(alpha: 0.1),
|
||||
foregroundColor: AppConstants.primaryColor,
|
||||
elevation: 0,
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(
|
||||
color: AppConstants.primaryColor.withValues(alpha: 0.3),
|
||||
// 解决方案和复现步骤按钮
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => _toggleBugExpanded(bug['id']),
|
||||
icon: Icon(
|
||||
isExpanded ? Icons.expand_less : Icons.expand_more,
|
||||
size: 18,
|
||||
),
|
||||
label: Text(
|
||||
isExpanded ? '收起解决方案' : '查看解决方案',
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppConstants.primaryColor.withValues(
|
||||
alpha: 0.1,
|
||||
),
|
||||
foregroundColor: AppConstants.primaryColor,
|
||||
elevation: 0,
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(
|
||||
color: AppConstants.primaryColor.withValues(
|
||||
alpha: 0.3,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => _toggleReproductionExpanded(bug['id']),
|
||||
icon: Icon(
|
||||
bug['reproductionExpanded']
|
||||
? Icons.expand_less
|
||||
: Icons.expand_more,
|
||||
size: 18,
|
||||
),
|
||||
label: Text(
|
||||
bug['reproductionExpanded'] ? '收起复现' : '查看复现',
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppConstants.secondaryColor
|
||||
.withValues(alpha: 0.1),
|
||||
foregroundColor: const Color(0xFF018786), // 更深的青色
|
||||
elevation: 0,
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(
|
||||
color: const Color(
|
||||
0xFF018786,
|
||||
).withValues(alpha: 0.3),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -447,35 +591,67 @@ class _BugListPageState extends State<BugListPage> {
|
||||
// 时间信息
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.schedule,
|
||||
size: 14,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
Icon(Icons.schedule, size: 14, color: Colors.grey[600]),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'预计解决: ${bug['resolveTime'] ?? '待定'}',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Icon(
|
||||
Icons.report,
|
||||
size: 14,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
Icon(Icons.report, size: 14, color: Colors.grey[600]),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
'报告时间: ${bug['reportTime'] ?? '未知'}',
|
||||
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
// 复现步骤区域(可展开/收起)
|
||||
if (bug['reproductionExpanded']) ...[
|
||||
const Divider(height: 1),
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[50],
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(12),
|
||||
bottomRight: Radius.circular(12),
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.replay,
|
||||
color: const Color(0xFF018786), // 更深的青色
|
||||
size: 16,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'复现步骤',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[600],
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: const Color(0xFF018786), // 更深的青色
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
bug['reproduction'] ?? '暂无复现步骤',
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
color: Colors.black54,
|
||||
height: 1.4,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -153,7 +153,6 @@ class _HistoryPageState extends State<HistoryPage> {
|
||||
_showSnackBar('删除失败');
|
||||
}
|
||||
} catch (e) {
|
||||
print('删除历史记录失败: $e');
|
||||
_showSnackBar('删除失败');
|
||||
}
|
||||
}
|
||||
@@ -170,7 +169,6 @@ class _HistoryPageState extends State<HistoryPage> {
|
||||
_showSnackBar('无数据可导出');
|
||||
}
|
||||
} catch (e) {
|
||||
print('导出历史记录失败: $e');
|
||||
_showSnackBar('导出失败');
|
||||
}
|
||||
}
|
||||
@@ -239,7 +237,6 @@ class _HistoryPageState extends State<HistoryPage> {
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
print('获取统计失败: $e');
|
||||
_showSnackBar('获取统计失败');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,6 @@ class _DistinguishPageState extends State<DistinguishPage> {
|
||||
try {
|
||||
return jsonDecode(record) as Map<String, dynamic>;
|
||||
} catch (e) {
|
||||
print('解析记录失败: $e');
|
||||
return <String, dynamic>{};
|
||||
}
|
||||
})
|
||||
@@ -75,7 +74,7 @@ class _DistinguishPageState extends State<DistinguishPage> {
|
||||
// 加载统计数据
|
||||
await _loadStatistics();
|
||||
} catch (e) {
|
||||
print('加载答题记录失败: $e');
|
||||
// 加载失败
|
||||
} finally {
|
||||
setState(() {
|
||||
_isLoading = false;
|
||||
@@ -121,7 +120,7 @@ class _DistinguishPageState extends State<DistinguishPage> {
|
||||
// 计算诗词水平
|
||||
_calculatePoetryLevel();
|
||||
} catch (e) {
|
||||
print('加载统计数据失败: $e');
|
||||
// 加载失败
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,7 +461,7 @@ $_poetryLevel
|
||||
context,
|
||||
).showSnackBar(const SnackBar(content: Text('答题记录已清空')));
|
||||
} catch (e) {
|
||||
print('清空记录失败: $e');
|
||||
// 清空失败
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ class PoetryLevelManager with NetworkListenerMixin {
|
||||
_offlineQuestions.add(map);
|
||||
}
|
||||
} catch (e) {
|
||||
print('解析离线数据失败: $e');
|
||||
// 解析失败,跳过
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ class PoetryLevelManager with NetworkListenerMixin {
|
||||
_currentIndex = 0;
|
||||
}
|
||||
} catch (e) {
|
||||
print('加载离线缓存失败: $e');
|
||||
// 加载失败
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,17 +103,13 @@ class PoetryLevelManager with NetworkListenerMixin {
|
||||
Map<String, dynamic> _parseStringToMap(String str) {
|
||||
final result = <String, dynamic>{};
|
||||
|
||||
print('开始解析字符串: $str');
|
||||
|
||||
try {
|
||||
// 尝试JSON解析
|
||||
final jsonMap = jsonDecode(str);
|
||||
if (jsonMap is Map<String, dynamic>) {
|
||||
print('JSON解析成功: $jsonMap');
|
||||
return jsonMap;
|
||||
}
|
||||
} catch (e) {
|
||||
print('JSON解析失败: $e');
|
||||
// 不是JSON格式,尝试其他解析方式
|
||||
}
|
||||
|
||||
@@ -144,7 +140,6 @@ class PoetryLevelManager with NetworkListenerMixin {
|
||||
}
|
||||
}
|
||||
|
||||
print('解析结果: $result');
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -226,8 +221,6 @@ class PoetryLevelManager with NetworkListenerMixin {
|
||||
isOffline: false,
|
||||
);
|
||||
} catch (e) {
|
||||
print('初始化题目失败: $e');
|
||||
|
||||
// 尝试加载离线缓存
|
||||
final hasCache = await _hasCachedData();
|
||||
if (hasCache) {
|
||||
@@ -363,15 +356,11 @@ class PoetryLevelManager with NetworkListenerMixin {
|
||||
|
||||
/// 格式化离线题目数据
|
||||
Map<String, dynamic> _formatOfflineQuestion(Map<String, dynamic> data) {
|
||||
print('格式化离线题目,原始数据: $data');
|
||||
|
||||
// 检查是否已经是标准格式
|
||||
if (data.containsKey('question') && data.containsKey('options')) {
|
||||
final options = data['options'];
|
||||
print('发现options字段,类型: ${options.runtimeType}, 值: $options');
|
||||
// 确保options是List类型
|
||||
if (options is List) {
|
||||
print('options已经是List类型,直接返回');
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -387,49 +376,37 @@ class PoetryLevelManager with NetworkListenerMixin {
|
||||
'options': <Map<String, dynamic>>[],
|
||||
};
|
||||
|
||||
print('构建基础数据: $result');
|
||||
|
||||
// 尝试解析options字段
|
||||
dynamic optionsData = data['options'];
|
||||
if (optionsData != null) {
|
||||
print('开始解析options,类型: ${optionsData.runtimeType}');
|
||||
if (optionsData is List) {
|
||||
// 已经是List,直接使用
|
||||
result['options'] = optionsData;
|
||||
print('options是List,直接使用');
|
||||
} else if (optionsData is String) {
|
||||
// 是String,尝试解析为List
|
||||
try {
|
||||
print('options是String,尝试解析: $optionsData');
|
||||
final parsedOptions = jsonDecode(optionsData);
|
||||
print('解析结果类型: ${parsedOptions.runtimeType}');
|
||||
if (parsedOptions is List) {
|
||||
result['options'] = parsedOptions;
|
||||
print('options解析成功为List');
|
||||
}
|
||||
} catch (e) {
|
||||
print('解析options字符串失败: $e');
|
||||
// 解析失败
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print('当前options: ${result['options']}');
|
||||
|
||||
// 如果没有有效的options,尝试从其他字段构建
|
||||
if ((result['options'] as List).isEmpty) {
|
||||
print('options为空,尝试从其他字段构建');
|
||||
final options = <Map<String, dynamic>>[];
|
||||
for (int i = 1; i <= 4; i++) {
|
||||
final optionKey = 'option_$i';
|
||||
if (data.containsKey(optionKey)) {
|
||||
options.add({'index': i, 'content': data[optionKey]});
|
||||
print('从$optionKey构建选项');
|
||||
}
|
||||
}
|
||||
result['options'] = options;
|
||||
}
|
||||
|
||||
print('最终格式化结果: $result');
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -375,7 +375,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
print('保存答题记录失败: $e');
|
||||
// 保存失败
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ class _ProfilePageState extends State<ProfilePage>
|
||||
|
||||
setState(() {});
|
||||
} catch (e) {
|
||||
print('加载答题统计失败: $e');
|
||||
// 加载失败
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import '../../../constants/app_constants.dart';
|
||||
import '../../../utils/audio_manager.dart';
|
||||
import './widgets.dart';
|
||||
import '../../home/home-load.dart';
|
||||
import '../../../controllers/load/locally.dart';
|
||||
@@ -20,7 +21,7 @@ class AppFunSettingsPage extends StatefulWidget {
|
||||
class _AppFunSettingsPageState extends State<AppFunSettingsPage> {
|
||||
bool _autoRefreshEnabled = false;
|
||||
bool _debugInfoEnabled = false;
|
||||
bool _soundEnabled = true;
|
||||
bool _soundEnabled = false; // 默认关闭
|
||||
bool _vibrationEnabled = true;
|
||||
bool _darkModeEnabled = false;
|
||||
bool _preloadEnabled = true;
|
||||
@@ -31,6 +32,7 @@ class _AppFunSettingsPageState extends State<AppFunSettingsPage> {
|
||||
static const String _autoRefreshKey = 'auto_refresh_enabled';
|
||||
static const String _debugInfoKey = 'debug_info_enabled';
|
||||
static const String _globalTipsKey = 'global_tips_enabled'; // 添加全局Tips开关key
|
||||
static const String _soundEnabledKey = 'sound_enabled'; // 声音反馈开关key
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -47,6 +49,7 @@ class _AppFunSettingsPageState extends State<AppFunSettingsPage> {
|
||||
_globalTipsEnabled =
|
||||
prefs.getBool(_globalTipsKey) ?? true; // 加载全局Tips开关状态
|
||||
_preloadEnabled = prefs.getBool('preload_enabled') ?? true;
|
||||
_soundEnabled = prefs.getBool(_soundEnabledKey) ?? false; // 加载声音反馈状态
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -82,13 +85,15 @@ class _AppFunSettingsPageState extends State<AppFunSettingsPage> {
|
||||
}
|
||||
}
|
||||
|
||||
// 设置全局Tips开关
|
||||
Future<void> _setGlobalTips(bool value) async {
|
||||
// 设置声音反馈
|
||||
Future<void> _setSoundEnabled(bool value) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setBool(_globalTipsKey, value);
|
||||
await prefs.setBool(_soundEnabledKey, value);
|
||||
// 更新 AudioManager 的静音状态
|
||||
AudioManager().setMuted(!value);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_globalTipsEnabled = value;
|
||||
_soundEnabled = value;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -159,14 +164,22 @@ class _AppFunSettingsPageState extends State<AppFunSettingsPage> {
|
||||
'显示一些使用技巧',
|
||||
Icons.volume_up,
|
||||
_globalTipsEnabled,
|
||||
(value) => _setGlobalTips(value),
|
||||
(value) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setBool(_globalTipsKey, value);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_globalTipsEnabled = value;
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
_buildSwitchItem(
|
||||
'声音反馈',
|
||||
'操作时播放提示音',
|
||||
Icons.volume_up,
|
||||
_soundEnabled,
|
||||
(value) => setState(() => _soundEnabled = value),
|
||||
_setSoundEnabled,
|
||||
),
|
||||
_buildSwitchItem(
|
||||
'震动反馈',
|
||||
|
||||
@@ -173,16 +173,10 @@ class _OfflineDataPageState extends State<OfflineDataPage> {
|
||||
if (response.isSuccess && response.jsonData != null) {
|
||||
final responseData = response.jsonData;
|
||||
|
||||
print('API完整响应: $responseData');
|
||||
|
||||
// 检查API返回格式
|
||||
if (responseData['code'] == 0 && responseData['data'] != null) {
|
||||
final itemData = responseData['data'] as Map<String, dynamic>;
|
||||
|
||||
print('API返回的data字段: $itemData');
|
||||
print('API返回的options字段: ${itemData['options']}');
|
||||
print('options字段类型: ${itemData['options']?.runtimeType}');
|
||||
|
||||
// 对于答题数据,确保options字段被正确序列化
|
||||
if (_selectedType == DownloadType.quiz) {
|
||||
// 深拷贝数据,避免修改原始数据
|
||||
@@ -194,22 +188,16 @@ class _OfflineDataPageState extends State<OfflineDataPage> {
|
||||
if (dataToStore['options'] is List) {
|
||||
// 将List转换为JSON字符串
|
||||
dataToStore['options'] = jsonEncode(dataToStore['options']);
|
||||
print('存储答题数据options: ${dataToStore['options']}');
|
||||
} else if (dataToStore['options'] is String) {
|
||||
// 已经是字符串,直接使用
|
||||
print('options已经是字符串,直接使用: ${dataToStore['options']}');
|
||||
} else {
|
||||
print('options类型异常: ${dataToStore['options'].runtimeType}');
|
||||
}
|
||||
} else {
|
||||
print('警告:options字段不存在或为null');
|
||||
// 如果没有options,添加一个空数组
|
||||
dataToStore['options'] = jsonEncode([]);
|
||||
}
|
||||
|
||||
// 将整个Map转换为JSON字符串存储
|
||||
final storedString = jsonEncode(dataToStore);
|
||||
print('存储答题数据完整: $storedString');
|
||||
currentData.add(storedString);
|
||||
} else {
|
||||
currentData.add(itemData.toString());
|
||||
@@ -231,8 +219,6 @@ class _OfflineDataPageState extends State<OfflineDataPage> {
|
||||
_cachedCount = currentData.length;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
print('API返回错误: ${responseData['msg'] ?? '未知错误'}');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user