重构
This commit is contained in:
67
CHANGELOG.md
67
CHANGELOG.md
@@ -4,61 +4,20 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## [1.3.7] - 2026-03-30
|
## [1.3.6] - 2026-03-31
|
||||||
|
|
||||||
### 新增
|
### 优化
|
||||||
- 🎵 **点击音效功能**
|
- 🏷️ **文件重命名与统一**
|
||||||
- 新增音频管理类 `lib/utils/audio_manager.dart`,使用audioplayers库管理音效播放
|
- 将 `sqlite_storage_controller.dart` 重命名为 `shared_preferences_storage_controller.dart`
|
||||||
- 在首页点击诗词卡片时播放音效 `assets/audios/deep.mp3`
|
- 将类名 `SQLiteStorageController` 重命名为 `SharedPreferencesStorageController`
|
||||||
- 在点击"下一条"按钮时播放音效
|
- 更新所有引用该文件的导入语句和类名调用
|
||||||
- 在点击"点赞"按钮时播放音效
|
- 涉及文件:
|
||||||
- 修改 `lib/views/home/home_page.dart`,初始化音频管理器并在点赞、下一条事件中添加音效
|
- `lib/main.dart`
|
||||||
- 修改 `lib/views/home/home_part.dart`,在诗词卡片点击事件中添加音效
|
- `lib/controllers/history_controller.dart`
|
||||||
- 支持静音控制,可通过AudioManager设置静音状态
|
- `lib/views/profile/profile_page.dart`
|
||||||
|
- `lib/views/profile/level/poetry.dart`
|
||||||
### 修复
|
- `lib/views/profile/level/distinguish.dart`
|
||||||
- 📁 **音频文件声明**
|
- 保持功能不变,仅统一命名规范
|
||||||
- 在 `pubspec.yaml` 中添加 `assets/audios/deep.mp3` 音频文件的声明,确保应用能正确加载音频资源
|
|
||||||
- 🔊 **音频播放阻塞UI修复**
|
|
||||||
- 修复声音开关打开时主页刷新点不动的问题
|
|
||||||
- 修复点击按钮时没有声音的问题
|
|
||||||
- 将音频播放改为非阻塞方式,避免等待播放完成
|
|
||||||
- 修改 `lib/utils/audio_manager.dart`,移除 `_playSound` 方法中的 `await`
|
|
||||||
- 修改 `lib/views/home/home_page.dart` 和 `lib/views/home/home_part.dart`,移除音频播放调用的 `await`
|
|
||||||
- 确保音频播放不影响UI响应速度
|
|
||||||
- 🔊 **音频重复播放修复**
|
|
||||||
- 修复只有第一次播放声音,后续播放无声音的问题
|
|
||||||
- 简化音频播放逻辑,移除复杂的音频上下文设置
|
|
||||||
- 使用单个 AudioPlayer 实例,避免重复创建
|
|
||||||
- 添加播放状态标志,防止重复播放
|
|
||||||
- 播放前停止当前播放,确保音频可以重复播放
|
|
||||||
|
|
||||||
### 功能优化
|
|
||||||
- 🔊 **声音反馈开关**
|
|
||||||
- 在 `lib/views/profile/settings/app_fun.dart` 中添加声音反馈开关
|
|
||||||
- 默认关闭声音反馈,可在设置中开启
|
|
||||||
- 状态持久化到 SharedPreferences
|
|
||||||
- 与 AudioManager 集成,控制首页音效播放
|
|
||||||
- 🔊 **悬浮按钮音频播放**
|
|
||||||
- 修改 `lib/views/home/home_part.dart` 中的悬浮按钮组件
|
|
||||||
- 为上一条、下一条、点赞按钮添加音频播放功能
|
|
||||||
- 确保操作时的声音反馈与设置中的开关状态同步
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## [1.3.6] - 2026-03-30
|
|
||||||
|
|
||||||
### 新增
|
|
||||||
- 🐛 **已知bug列表功能**
|
|
||||||
- 新增bug列表页面 `lib/views/profile/components/bug_list_page.dart`
|
|
||||||
- 从下到上弹出页面显示已知bug、解决方法和解决时间
|
|
||||||
- 支持下拉刷新和滚动查看,列表可下滑
|
|
||||||
- 显示bug优先级(高/中/低)、状态(已解决/解决中/待解决)
|
|
||||||
- 显示影响用户范围、报告时间和预计解决时间
|
|
||||||
- 提供详细的解决方案描述
|
|
||||||
- 新增复现步骤功能,支持查看和收起复现步骤
|
|
||||||
- 修改个人页面"已知bug"按钮点击事件,从显示SnackBar改为弹出bug列表页面
|
|
||||||
- 文件:`lib/views/profile/profile_page.dart`
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
/// 最新变化: 添加笔记管理功能
|
/// 最新变化: 添加笔记管理功能
|
||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'sqlite_storage_controller.dart';
|
import 'shared_preferences_storage_controller.dart';
|
||||||
|
|
||||||
/// 历史记录控制器类
|
/// 历史记录控制器类
|
||||||
/// 负责管理诗词浏览历史记录和点赞记录的本地存储和读取
|
/// 负责管理诗词浏览历史记录和点赞记录的本地存储和读取
|
||||||
@@ -19,7 +19,7 @@ class HistoryController {
|
|||||||
/// 返回按时间倒序排列的诗词历史记录
|
/// 返回按时间倒序排列的诗词历史记录
|
||||||
static Future<List<Map<String, dynamic>>> getHistory() async {
|
static Future<List<Map<String, dynamic>>> getHistory() async {
|
||||||
try {
|
try {
|
||||||
final historyJson = await SQLiteStorageController.getString(
|
final historyJson = await SharedPreferencesStorageController.getString(
|
||||||
_historyKey,
|
_historyKey,
|
||||||
defaultValue: '[]',
|
defaultValue: '[]',
|
||||||
);
|
);
|
||||||
@@ -48,7 +48,7 @@ class HistoryController {
|
|||||||
_isAdding = true;
|
_isAdding = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final historyJson = await SQLiteStorageController.getString(
|
final historyJson = await SharedPreferencesStorageController.getString(
|
||||||
_historyKey,
|
_historyKey,
|
||||||
defaultValue: '[]',
|
defaultValue: '[]',
|
||||||
);
|
);
|
||||||
@@ -73,7 +73,10 @@ class HistoryController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final updatedHistoryJson = json.encode(historyList);
|
final updatedHistoryJson = json.encode(historyList);
|
||||||
await SQLiteStorageController.setString(_historyKey, updatedHistoryJson);
|
await SharedPreferencesStorageController.setString(
|
||||||
|
_historyKey,
|
||||||
|
updatedHistoryJson,
|
||||||
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -88,7 +91,7 @@ class HistoryController {
|
|||||||
/// 返回是否移除成功
|
/// 返回是否移除成功
|
||||||
static Future<bool> removeFromHistory(int poetryId) async {
|
static Future<bool> removeFromHistory(int poetryId) async {
|
||||||
try {
|
try {
|
||||||
final historyJson = await SQLiteStorageController.getString(
|
final historyJson = await SharedPreferencesStorageController.getString(
|
||||||
_historyKey,
|
_historyKey,
|
||||||
defaultValue: '[]',
|
defaultValue: '[]',
|
||||||
);
|
);
|
||||||
@@ -100,7 +103,7 @@ class HistoryController {
|
|||||||
|
|
||||||
if (historyList.length < originalLength) {
|
if (historyList.length < originalLength) {
|
||||||
final updatedHistoryJson = json.encode(historyList);
|
final updatedHistoryJson = json.encode(historyList);
|
||||||
await SQLiteStorageController.setString(
|
await SharedPreferencesStorageController.setString(
|
||||||
_historyKey,
|
_historyKey,
|
||||||
updatedHistoryJson,
|
updatedHistoryJson,
|
||||||
);
|
);
|
||||||
@@ -118,7 +121,7 @@ class HistoryController {
|
|||||||
/// 返回是否清空成功
|
/// 返回是否清空成功
|
||||||
static Future<bool> clearHistory() async {
|
static Future<bool> clearHistory() async {
|
||||||
try {
|
try {
|
||||||
await SQLiteStorageController.remove(_historyKey);
|
await SharedPreferencesStorageController.remove(_historyKey);
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
@@ -266,7 +269,7 @@ class HistoryController {
|
|||||||
/// 返回点赞的诗词列表
|
/// 返回点赞的诗词列表
|
||||||
static Future<List<Map<String, dynamic>>> getLikedHistory() async {
|
static Future<List<Map<String, dynamic>>> getLikedHistory() async {
|
||||||
try {
|
try {
|
||||||
final likedJson = await SQLiteStorageController.getString(
|
final likedJson = await SharedPreferencesStorageController.getString(
|
||||||
_likedKey,
|
_likedKey,
|
||||||
defaultValue: '[]',
|
defaultValue: '[]',
|
||||||
);
|
);
|
||||||
@@ -283,7 +286,7 @@ class HistoryController {
|
|||||||
|
|
||||||
static Future<bool> addToLiked(Map<String, dynamic> poetryData) async {
|
static Future<bool> addToLiked(Map<String, dynamic> poetryData) async {
|
||||||
try {
|
try {
|
||||||
final likedJson = await SQLiteStorageController.getString(
|
final likedJson = await SharedPreferencesStorageController.getString(
|
||||||
_likedKey,
|
_likedKey,
|
||||||
defaultValue: '[]',
|
defaultValue: '[]',
|
||||||
);
|
);
|
||||||
@@ -307,7 +310,10 @@ class HistoryController {
|
|||||||
likedList.insert(0, enrichedPoetryData);
|
likedList.insert(0, enrichedPoetryData);
|
||||||
|
|
||||||
final updatedLikedJson = json.encode(likedList);
|
final updatedLikedJson = json.encode(likedList);
|
||||||
await SQLiteStorageController.setString(_likedKey, updatedLikedJson);
|
await SharedPreferencesStorageController.setString(
|
||||||
|
_likedKey,
|
||||||
|
updatedLikedJson,
|
||||||
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -317,7 +323,7 @@ class HistoryController {
|
|||||||
|
|
||||||
static Future<bool> removeLikedPoetry(String poetryId) async {
|
static Future<bool> removeLikedPoetry(String poetryId) async {
|
||||||
try {
|
try {
|
||||||
final likedJson = await SQLiteStorageController.getString(
|
final likedJson = await SharedPreferencesStorageController.getString(
|
||||||
_likedKey,
|
_likedKey,
|
||||||
defaultValue: '[]',
|
defaultValue: '[]',
|
||||||
);
|
);
|
||||||
@@ -329,7 +335,10 @@ class HistoryController {
|
|||||||
|
|
||||||
if (likedList.length < originalLength) {
|
if (likedList.length < originalLength) {
|
||||||
final updatedLikedJson = json.encode(likedList);
|
final updatedLikedJson = json.encode(likedList);
|
||||||
await SQLiteStorageController.setString(_likedKey, updatedLikedJson);
|
await SharedPreferencesStorageController.setString(
|
||||||
|
_likedKey,
|
||||||
|
updatedLikedJson,
|
||||||
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -351,7 +360,7 @@ class HistoryController {
|
|||||||
|
|
||||||
static Future<bool> clearLikedHistory() async {
|
static Future<bool> clearLikedHistory() async {
|
||||||
try {
|
try {
|
||||||
await SQLiteStorageController.remove(_likedKey);
|
await SharedPreferencesStorageController.remove(_likedKey);
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
@@ -385,7 +394,9 @@ class HistoryController {
|
|||||||
/// 返回笔记列表(置顶的排在前面)
|
/// 返回笔记列表(置顶的排在前面)
|
||||||
static Future<List<Map<String, dynamic>>> getNotes() async {
|
static Future<List<Map<String, dynamic>>> getNotes() async {
|
||||||
try {
|
try {
|
||||||
final notesJson = await SQLiteStorageController.getString(_notesKey);
|
final notesJson = await SharedPreferencesStorageController.getString(
|
||||||
|
_notesKey,
|
||||||
|
);
|
||||||
if (notesJson.isEmpty) {
|
if (notesJson.isEmpty) {
|
||||||
// 返回默认笔记示例
|
// 返回默认笔记示例
|
||||||
return _getDefaultNotes();
|
return _getDefaultNotes();
|
||||||
@@ -529,7 +540,7 @@ class HistoryController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final notesJson = json.encode(notes);
|
final notesJson = json.encode(notes);
|
||||||
await SQLiteStorageController.setString(_notesKey, notesJson);
|
await SharedPreferencesStorageController.setString(_notesKey, notesJson);
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -557,7 +568,7 @@ class HistoryController {
|
|||||||
notes.removeWhere((n) => n['id'] == noteId);
|
notes.removeWhere((n) => n['id'] == noteId);
|
||||||
|
|
||||||
final notesJson = json.encode(notes);
|
final notesJson = json.encode(notes);
|
||||||
await SQLiteStorageController.setString(_notesKey, notesJson);
|
await SharedPreferencesStorageController.setString(_notesKey, notesJson);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -578,7 +589,7 @@ class HistoryController {
|
|||||||
notes[index]['isPinned'] = !currentPinned;
|
notes[index]['isPinned'] = !currentPinned;
|
||||||
|
|
||||||
final notesJson = json.encode(notes);
|
final notesJson = json.encode(notes);
|
||||||
await SQLiteStorageController.setString(_notesKey, notesJson);
|
await SharedPreferencesStorageController.setString(_notesKey, notesJson);
|
||||||
|
|
||||||
return !currentPinned;
|
return !currentPinned;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -604,7 +615,7 @@ class HistoryController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final notesJson = json.encode(notes);
|
final notesJson = json.encode(notes);
|
||||||
await SQLiteStorageController.setString(_notesKey, notesJson);
|
await SharedPreferencesStorageController.setString(_notesKey, notesJson);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
/// 时间: 2025-03-25
|
/// 时间: 2025-03-25
|
||||||
/// 功能: SharedPreferences存储控制器
|
/// 功能: SharedPreferences存储控制器
|
||||||
/// 介绍: 使用SharedPreferences实现本地存储功能,替代SQLite
|
/// 介绍: 使用SharedPreferences实现本地存储功能
|
||||||
/// 最新变化: 将SQLite替换为SharedPreferences实现
|
/// 最新变化: 重命名为SharedPreferencesStorageController
|
||||||
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
/// SharedPreferences存储控制器类
|
/// SharedPreferences存储控制器类
|
||||||
/// 负责管理本地键值对存储,基于SharedPreferences实现
|
/// 负责管理本地键值对存储,基于SharedPreferences实现
|
||||||
class SQLiteStorageController {
|
class SharedPreferencesStorageController {
|
||||||
static SharedPreferences? _prefs;
|
static SharedPreferences? _prefs;
|
||||||
|
|
||||||
/// 初始化SharedPreferences
|
/// 初始化SharedPreferences
|
||||||
@@ -4,12 +4,12 @@ import 'utils/app_initializer.dart';
|
|||||||
import 'utils/force_guide_checker.dart';
|
import 'utils/force_guide_checker.dart';
|
||||||
import 'routes/app_routes.dart';
|
import 'routes/app_routes.dart';
|
||||||
import 'constants/app_constants.dart';
|
import 'constants/app_constants.dart';
|
||||||
import 'controllers/sqlite_storage_controller.dart';
|
import 'controllers/shared_preferences_storage_controller.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
await SQLiteStorageController.init();
|
await SharedPreferencesStorageController.init();
|
||||||
|
|
||||||
final result = await AppInitializer.initialize();
|
final result = await AppInitializer.initialize();
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
/// 最新变化: 新增 NetworkEventType.search 与 sendSearchEvent,供诗词搜索页通知
|
/// 最新变化: 新增 NetworkEventType.search 与 sendSearchEvent,供诗词搜索页通知
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
|
|
||||||
/// 网络状态枚举
|
/// 网络状态枚举
|
||||||
enum NetworkStatus {
|
enum NetworkStatus {
|
||||||
@@ -41,7 +40,8 @@ class NetworkEvent {
|
|||||||
|
|
||||||
/// 网络监听服务
|
/// 网络监听服务
|
||||||
class NetworkListenerService {
|
class NetworkListenerService {
|
||||||
static final NetworkListenerService _instance = NetworkListenerService._internal();
|
static final NetworkListenerService _instance =
|
||||||
|
NetworkListenerService._internal();
|
||||||
factory NetworkListenerService() => _instance;
|
factory NetworkListenerService() => _instance;
|
||||||
NetworkListenerService._internal();
|
NetworkListenerService._internal();
|
||||||
|
|
||||||
@@ -89,10 +89,7 @@ class NetworkListenerService {
|
|||||||
/// 发送错误事件
|
/// 发送错误事件
|
||||||
void sendErrorEvent(NetworkEventType type, {String? errorMessage}) {
|
void sendErrorEvent(NetworkEventType type, {String? errorMessage}) {
|
||||||
_updateStatus(NetworkStatus.error);
|
_updateStatus(NetworkStatus.error);
|
||||||
_eventController.add(NetworkEvent(
|
_eventController.add(NetworkEvent(type: type, errorMessage: errorMessage));
|
||||||
type: type,
|
|
||||||
errorMessage: errorMessage,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 发送点赞事件
|
/// 发送点赞事件
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:audioplayers/audioplayers.dart';
|
import 'package:audioplayers/audioplayers.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
/// 时间: 2026-03-30
|
/// 时间: 2026-03-30
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
|
|
||||||
class HttpClient {
|
class HttpClient {
|
||||||
static const String _baseUrl = 'https://yy.vogov.cn/api/';
|
static const String _baseUrl = 'https://yy.vogov.cn/api/';
|
||||||
@@ -89,7 +88,7 @@ class HttpClient {
|
|||||||
final options = Options(
|
final options = Options(
|
||||||
method: method,
|
method: method,
|
||||||
headers: headers != null
|
headers: headers != null
|
||||||
? {..._options.headers!, ...headers}
|
? {..._options.headers, ...headers}
|
||||||
: _options.headers,
|
: _options.headers,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -165,7 +164,7 @@ class HttpClient {
|
|||||||
final options = Options(
|
final options = Options(
|
||||||
method: method,
|
method: method,
|
||||||
headers: headers != null
|
headers: headers != null
|
||||||
? {..._options.headers!, ...headers}
|
? {..._options.headers, ...headers}
|
||||||
: _options.headers,
|
: _options.headers,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
/// 最新变化: 新增 search.php 搜索接口(与 API_DOCUMENTATION.md 一致)
|
/// 最新变化: 新增 search.php 搜索接口(与 API_DOCUMENTATION.md 一致)
|
||||||
|
|
||||||
import 'http_client.dart';
|
import 'http_client.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
|
|
||||||
class PoetryApi {
|
class PoetryApi {
|
||||||
static const String _endpoint = 'pms.php';
|
static const String _endpoint = 'pms.php';
|
||||||
|
|
||||||
/// 全文搜索(见 lib/services/API_DOCUMENTATION.md 第二节)
|
/// 全文搜索(见 lib/services/API_DOCUMENTATION.md 第二节)
|
||||||
static const String _searchEndpoint = 'searchs.php';
|
static const String _searchEndpoint = 'searchs.php';
|
||||||
|
|
||||||
@@ -26,7 +26,10 @@ class PoetryApi {
|
|||||||
queryParams['tag'] = tag;
|
queryParams['tag'] = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
final response = await HttpClient.get(_endpoint, queryParameters: queryParams);
|
final response = await HttpClient.get(
|
||||||
|
_endpoint,
|
||||||
|
queryParameters: queryParams,
|
||||||
|
);
|
||||||
|
|
||||||
if (!response.isSuccess) {
|
if (!response.isSuccess) {
|
||||||
throw HttpException('获取诗词失败1: ${response.message}');
|
throw HttpException('获取诗词失败1: ${response.message}');
|
||||||
@@ -111,7 +114,10 @@ class PoetryApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 按朝代和标签获取诗词
|
/// 按朝代和标签获取诗词
|
||||||
static Future<PoetryResponse> getPoetryByDynastyAndTag(String dynasty, String tag) async {
|
static Future<PoetryResponse> getPoetryByDynastyAndTag(
|
||||||
|
String dynasty,
|
||||||
|
String tag,
|
||||||
|
) async {
|
||||||
return getRandomPoetry(dynasty: dynasty, tag: tag);
|
return getRandomPoetry(dynasty: dynasty, tag: tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,9 +173,12 @@ class PoetryApi {
|
|||||||
|
|
||||||
// 从 pagination 中获取分页信息
|
// 从 pagination 中获取分页信息
|
||||||
final pagination = raw['pagination'] as Map<String, dynamic>? ?? {};
|
final pagination = raw['pagination'] as Map<String, dynamic>? ?? {};
|
||||||
final totalCount = int.tryParse(pagination['total_count']?.toString() ?? '0') ?? 0;
|
final totalCount =
|
||||||
final currentPage = int.tryParse(pagination['current_page']?.toString() ?? '$page') ?? page;
|
int.tryParse(pagination['total_count']?.toString() ?? '0') ?? 0;
|
||||||
final pageSize = int.tryParse(pagination['page_size']?.toString() ?? '$limit') ?? limit;
|
final currentPage =
|
||||||
|
int.tryParse(pagination['current_page']?.toString() ?? '$page') ?? page;
|
||||||
|
final pageSize =
|
||||||
|
int.tryParse(pagination['page_size']?.toString() ?? '$limit') ?? limit;
|
||||||
|
|
||||||
return SearchPoetryResult(
|
return SearchPoetryResult(
|
||||||
total: totalCount,
|
total: totalCount,
|
||||||
@@ -203,11 +212,7 @@ class PoetryResponse {
|
|||||||
final String message;
|
final String message;
|
||||||
final PoetryData? data;
|
final PoetryData? data;
|
||||||
|
|
||||||
PoetryResponse({
|
PoetryResponse({required this.code, required this.message, this.data});
|
||||||
required this.code,
|
|
||||||
required this.message,
|
|
||||||
this.data,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory PoetryResponse.fromJson(Map<String, dynamic> json) {
|
factory PoetryResponse.fromJson(Map<String, dynamic> json) {
|
||||||
return PoetryResponse(
|
return PoetryResponse(
|
||||||
@@ -218,18 +223,14 @@ class PoetryResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {'code': code, 'msg': message, 'data': data?.toJson()};
|
||||||
'code': code,
|
|
||||||
'msg': message,
|
|
||||||
'data': data?.toJson(),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 诗词数据模型
|
/// 诗词数据模型
|
||||||
class PoetryData {
|
class PoetryData {
|
||||||
final int id;
|
final int id;
|
||||||
final String name;// 精选诗句
|
final String name; // 精选诗句
|
||||||
final String alias; // 朝代
|
final String alias; // 朝代
|
||||||
final String keywords; // 标签
|
final String keywords; // 标签
|
||||||
final String introduce; // 译文/介绍
|
final String introduce; // 译文/介绍
|
||||||
@@ -323,7 +324,11 @@ class PoetryData {
|
|||||||
/// 获取标签列表
|
/// 获取标签列表
|
||||||
List<String> get keywordList {
|
List<String> get keywordList {
|
||||||
if (keywords.isEmpty) return [];
|
if (keywords.isEmpty) return [];
|
||||||
return keywords.split(',').map((k) => k.trim()).where((k) => k.isNotEmpty).toList();
|
return keywords
|
||||||
|
.split(',')
|
||||||
|
.map((k) => k.trim())
|
||||||
|
.where((k) => k.isNotEmpty)
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 生成星级显示
|
/// 生成星级显示
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import 'dart:io' as io show Platform;
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
|
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
|
||||||
import 'package:cookie_jar/cookie_jar.dart';
|
import 'package:cookie_jar/cookie_jar.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:platform_info/platform_info.dart';
|
import 'package:platform_info/platform_info.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../../constants/app_constants.dart';
|
import '../../constants/app_constants.dart';
|
||||||
import '../../utils/responsive_layout.dart';
|
|
||||||
|
|
||||||
/// 时间: 2026-03-25
|
/// 时间: 2026-03-25
|
||||||
/// 功能: 分类页面
|
/// 功能: 分类页面
|
||||||
@@ -14,27 +13,67 @@ class CategoryPage extends StatefulWidget {
|
|||||||
State<CategoryPage> createState() => _CategoryPageState();
|
State<CategoryPage> createState() => _CategoryPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _CategoryPageState extends State<CategoryPage> with SingleTickerProviderStateMixin {
|
class _CategoryPageState extends State<CategoryPage>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
late TabController _tabController;
|
late TabController _tabController;
|
||||||
final List<String> _tabCategories = ['场景分类', '朝代分类'];
|
final List<String> _tabCategories = ['场景分类', '朝代分类'];
|
||||||
|
|
||||||
static const sceneData = {
|
static const sceneData = {
|
||||||
"节日": ["七夕节", "中秋节", "元宵节", "寒食节", "清明节", "端午节", "重阳节", "春节", "节日"],
|
"节日": ["七夕节", "中秋节", "元宵节", "寒食节", "清明节", "端午节", "重阳节", "春节", "节日"],
|
||||||
"季节": ["三月", "二月", "冬天", "夏天", "春天", "春季", "秋天"],
|
"季节": ["三月", "二月", "冬天", "夏天", "春天", "春季", "秋天"],
|
||||||
"古籍": ["三国志", "三国演义", "三字经", "中庸", "列子", "史记", "后汉书", "吕氏春秋", "商君书", "围炉夜话", "增广贤文", "墨子", "孙子兵法", "孟子", "小窗幽记", "尚书", "左传", "幼学琼林", "庄子", "战国策", "文心雕龙", "易传", "晋书", "汉书", "淮南子", "礼记", "管子", "红楼梦", "老子", "荀子", "菜根谭", "警世通言", "论语", "资治通鉴", "韩非子", "鬼谷子", "古籍", "格言联璧"],
|
"古籍": [
|
||||||
|
"三国志",
|
||||||
|
"三国演义",
|
||||||
|
"三字经",
|
||||||
|
"中庸",
|
||||||
|
"列子",
|
||||||
|
"史记",
|
||||||
|
"后汉书",
|
||||||
|
"吕氏春秋",
|
||||||
|
"商君书",
|
||||||
|
"围炉夜话",
|
||||||
|
"增广贤文",
|
||||||
|
"墨子",
|
||||||
|
"孙子兵法",
|
||||||
|
"孟子",
|
||||||
|
"小窗幽记",
|
||||||
|
"尚书",
|
||||||
|
"左传",
|
||||||
|
"幼学琼林",
|
||||||
|
"庄子",
|
||||||
|
"战国策",
|
||||||
|
"文心雕龙",
|
||||||
|
"易传",
|
||||||
|
"晋书",
|
||||||
|
"汉书",
|
||||||
|
"淮南子",
|
||||||
|
"礼记",
|
||||||
|
"管子",
|
||||||
|
"红楼梦",
|
||||||
|
"老子",
|
||||||
|
"荀子",
|
||||||
|
"菜根谭",
|
||||||
|
"警世通言",
|
||||||
|
"论语",
|
||||||
|
"资治通鉴",
|
||||||
|
"韩非子",
|
||||||
|
"鬼谷子",
|
||||||
|
"古籍",
|
||||||
|
"格言联璧",
|
||||||
|
],
|
||||||
"情感": ["伤感", "励志", "友情", "思乡", "思念", "感恩", "爱国", "爱情", "离别"],
|
"情感": ["伤感", "励志", "友情", "思乡", "思念", "感恩", "爱国", "爱情", "离别"],
|
||||||
"景物": ["庐山", "泰山", "西湖", "长江", "黄河", "边塞", "田园", "山水", "夜景"],
|
"景物": ["庐山", "泰山", "西湖", "长江", "黄河", "边塞", "田园", "山水", "夜景"],
|
||||||
"天文气象": ["写云", "写雨", "写雪", "写风", "星星", "月亮", "流星"],
|
"天文气象": ["写云", "写雨", "写雪", "写风", "星星", "月亮", "流星"],
|
||||||
"动植物": ["写鸟", "柳树", "桃花", "梅花", "竹子", "荷花", "菊花"],
|
"动植物": ["写鸟", "柳树", "桃花", "梅花", "竹子", "荷花", "菊花"],
|
||||||
"语言文学": ["对联", "谚语", "一言", "读书", "哲理"],
|
"语言文学": ["对联", "谚语", "一言", "读书", "哲理"],
|
||||||
"其他": ["母亲", "老师", "户外", "礼物", "酒"]
|
"其他": ["母亲", "老师", "户外", "礼物", "酒"],
|
||||||
};
|
};
|
||||||
|
|
||||||
static const dynastyData = {
|
static const dynastyData = {
|
||||||
"主要朝代": ["唐代", "宋代", "元代", "明代", "清代"],
|
"主要朝代": ["唐代", "宋代", "元代", "明代", "清代"],
|
||||||
"古代朝代": ["南北朝", "五代", "隋代"],
|
"古代朝代": ["南北朝", "五代", "隋代"],
|
||||||
"近现代": ["近现代", "用户投稿", "管理员测试"],
|
"近现代": ["近现代", "用户投稿", "管理员测试"],
|
||||||
"其他": ["暂无朝代"]
|
"其他": ["暂无朝代"],
|
||||||
};
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -51,9 +90,6 @@ class _CategoryPageState extends State<CategoryPage> with SingleTickerProviderSt
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isDesktop = ResponsiveLayout.isDesktop(context);
|
|
||||||
final isTablet = ResponsiveLayout.isTablet(context);
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||||
body: Column(
|
body: Column(
|
||||||
@@ -65,7 +101,9 @@ class _CategoryPageState extends State<CategoryPage> with SingleTickerProviderSt
|
|||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: TabBar(
|
child: TabBar(
|
||||||
controller: _tabController,
|
controller: _tabController,
|
||||||
tabs: _tabCategories.map((category) => Tab(text: category)).toList(),
|
tabs: _tabCategories
|
||||||
|
.map((category) => Tab(text: category))
|
||||||
|
.toList(),
|
||||||
labelColor: AppConstants.primaryColor,
|
labelColor: AppConstants.primaryColor,
|
||||||
unselectedLabelColor: Colors.grey[600],
|
unselectedLabelColor: Colors.grey[600],
|
||||||
indicatorColor: AppConstants.primaryColor,
|
indicatorColor: AppConstants.primaryColor,
|
||||||
@@ -88,7 +126,10 @@ class _CategoryPageState extends State<CategoryPage> with SingleTickerProviderSt
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildCategoryGrid(Map<String, List<String>> data, String categoryType) {
|
Widget _buildCategoryGrid(
|
||||||
|
Map<String, List<String>> data,
|
||||||
|
String categoryType,
|
||||||
|
) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../../constants/app_constants.dart';
|
import '../../constants/app_constants.dart';
|
||||||
import '../../utils/responsive_layout.dart';
|
|
||||||
import '../../utils/http/http_client.dart';
|
import '../../utils/http/http_client.dart';
|
||||||
import '../../models/poetry_model.dart';
|
import '../../models/poetry_model.dart';
|
||||||
import '../../controllers/load/locally.dart';
|
import '../../controllers/load/locally.dart';
|
||||||
|
|||||||
@@ -23,14 +23,6 @@ class _RatePageState extends State<RatePage>
|
|||||||
int _debugBarCount = 7;
|
int _debugBarCount = 7;
|
||||||
bool _showDebugPanel = false;
|
bool _showDebugPanel = false;
|
||||||
|
|
||||||
// 活跃度阈值配置
|
|
||||||
final Map<String, int> _activityThresholds = {
|
|
||||||
'low': 1, // 1-5
|
|
||||||
'medium': 6, // 6-20
|
|
||||||
'high': 21, // 21-100
|
|
||||||
'veryHigh': 100, // 100+
|
|
||||||
};
|
|
||||||
|
|
||||||
// 模拟活跃度数据 (实际条数)
|
// 模拟活跃度数据 (实际条数)
|
||||||
List<int> _weekData = [];
|
List<int> _weekData = [];
|
||||||
List<List<int>> _monthData = [];
|
List<List<int>> _monthData = [];
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../constants/app_constants.dart';
|
import '../constants/app_constants.dart';
|
||||||
import '../utils/responsive_layout.dart';
|
import '../utils/responsive_layout.dart';
|
||||||
import '../utils/flutter_compatibility_fix.dart';
|
|
||||||
import '../widgets/tabbed_nav_app_bar.dart';
|
import '../widgets/tabbed_nav_app_bar.dart';
|
||||||
import 'active/active_search_page.dart';
|
import 'active/active_search_page.dart';
|
||||||
import 'active/category_page.dart';
|
import 'active/category_page.dart';
|
||||||
@@ -80,7 +79,6 @@ class _DiscoverPageState extends State<DiscoverPage>
|
|||||||
child: TabBarView(
|
child: TabBarView(
|
||||||
controller: _tabController,
|
controller: _tabController,
|
||||||
children: _categories.asMap().entries.map((entry) {
|
children: _categories.asMap().entries.map((entry) {
|
||||||
final index = entry.key;
|
|
||||||
final category = entry.value;
|
final category = entry.value;
|
||||||
// 搜索标签显示 ActiveSearchPage
|
// 搜索标签显示 ActiveSearchPage
|
||||||
if (category == '搜索') {
|
if (category == '搜索') {
|
||||||
|
|||||||
@@ -234,73 +234,4 @@ class _FavoritesPageState extends State<FavoritesPage>
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showFavoriteDetails(BuildContext context, int index, String category) {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: Text('$category详情'),
|
|
||||||
content: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text('分类: $category'),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Text('收藏时间: ${(index + 1) * 2}天前'),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
const Text('这是收藏内容的详细信息。'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
child: const Text('关闭'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleFavoriteAction(String action, int index) {
|
|
||||||
switch (action) {
|
|
||||||
case 'share':
|
|
||||||
ScaffoldMessenger.of(
|
|
||||||
context,
|
|
||||||
).showSnackBar(SnackBar(content: Text('分享了收藏${index + 1}')));
|
|
||||||
break;
|
|
||||||
case 'edit':
|
|
||||||
ScaffoldMessenger.of(
|
|
||||||
context,
|
|
||||||
).showSnackBar(SnackBar(content: Text('编辑了收藏${index + 1}')));
|
|
||||||
break;
|
|
||||||
case 'delete':
|
|
||||||
_showDeleteConfirm(index);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showDeleteConfirm(int index) {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: const Text('确认删除'),
|
|
||||||
content: Text('确定要删除收藏${index + 1}吗?'),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
child: const Text('取消'),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
ScaffoldMessenger.of(
|
|
||||||
context,
|
|
||||||
).showSnackBar(SnackBar(content: Text('已删除收藏${index + 1}')));
|
|
||||||
},
|
|
||||||
child: const Text('删除', style: TextStyle(color: Colors.red)),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import '../../../constants/app_constants.dart';
|
|||||||
import '../../../utils/http/poetry_api.dart';
|
import '../../../utils/http/poetry_api.dart';
|
||||||
import '../../../services/network_listener_service.dart';
|
import '../../../services/network_listener_service.dart';
|
||||||
import '../home/home_components.dart';
|
import '../home/home_components.dart';
|
||||||
import '../home/home_part.dart';
|
|
||||||
|
|
||||||
/// 点赞足迹页面
|
/// 点赞足迹页面
|
||||||
class FootprintPage extends StatefulWidget {
|
class FootprintPage extends StatefulWidget {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
/// 最新变化: 新建文件
|
/// 最新变化: 新建文件
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import '../../../utils/http/poetry_api.dart';
|
import '../../../utils/http/poetry_api.dart';
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ class _HomePageState extends State<HomePage>
|
|||||||
bool _isLoadingLike = false;
|
bool _isLoadingLike = false;
|
||||||
String _errorMessage = '';
|
String _errorMessage = '';
|
||||||
String _starDisplay = '';
|
String _starDisplay = '';
|
||||||
final String _historyKey = 'poetry_history';
|
|
||||||
List<Map<String, dynamic>> _historyList = [];
|
List<Map<String, dynamic>> _historyList = [];
|
||||||
int _currentHistoryIndex = -1;
|
int _currentHistoryIndex = -1;
|
||||||
late AnimationController _fadeController;
|
late AnimationController _fadeController;
|
||||||
@@ -41,7 +40,6 @@ class _HomePageState extends State<HomePage>
|
|||||||
|
|
||||||
// 动态加载状态
|
// 动态加载状态
|
||||||
bool _isLoadingNext = false;
|
bool _isLoadingNext = false;
|
||||||
bool _isLoadingPrevious = false;
|
|
||||||
Map<String, bool> _sectionLoadingStates = {
|
Map<String, bool> _sectionLoadingStates = {
|
||||||
'title': false,
|
'title': false,
|
||||||
'content': false,
|
'content': false,
|
||||||
|
|||||||
@@ -524,27 +524,20 @@ class _PoetryCardState extends State<PoetryCard> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
// 右边:星星和点赞
|
// 右边:星星和点赞
|
||||||
if (!isLoading &&
|
if (!isLoading)
|
||||||
(widget.poetryData.star != null ||
|
|
||||||
widget.poetryData.like != null ||
|
|
||||||
widget.poetryData.hitsTotal != null))
|
|
||||||
Row(
|
Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
if (widget.poetryData.star != null) ...[
|
|
||||||
Text(
|
Text(
|
||||||
PoetryDataUtils.generateStars(widget.poetryData.star),
|
PoetryDataUtils.generateStars(widget.poetryData.star),
|
||||||
style: const TextStyle(fontSize: 14),
|
style: const TextStyle(fontSize: 14),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
],
|
|
||||||
if (widget.poetryData.like != null) ...[
|
|
||||||
Text(
|
Text(
|
||||||
PoetryDataUtils.generateLikeText(widget.poetryData.like),
|
PoetryDataUtils.generateLikeText(widget.poetryData.like),
|
||||||
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
),
|
),
|
||||||
],
|
const SizedBox(width: 4),
|
||||||
if (widget.poetryData.hitsTotal != null) ...[
|
|
||||||
Text(
|
Text(
|
||||||
PoetryDataUtils.generateViewText(
|
PoetryDataUtils.generateViewText(
|
||||||
widget.poetryData.hitsTotal,
|
widget.poetryData.hitsTotal,
|
||||||
@@ -552,7 +545,6 @@ class _PoetryCardState extends State<PoetryCard> {
|
|||||||
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../constants/app_constants.dart';
|
import '../constants/app_constants.dart';
|
||||||
import '../routes/app_routes.dart';
|
|
||||||
import './home/home_page.dart';
|
import './home/home_page.dart';
|
||||||
import './discover_page.dart';
|
import './discover_page.dart';
|
||||||
import './favorites_page.dart';
|
import './favorites_page.dart';
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import '../../../constants/app_constants.dart';
|
import '../../../constants/app_constants.dart';
|
||||||
import '../../../config/app_config.dart';
|
|
||||||
|
|
||||||
/// 时间: 2026-03-27
|
/// 时间: 2026-03-27
|
||||||
/// 功能: 应用数据管理页面
|
/// 功能: 应用数据管理页面
|
||||||
@@ -222,39 +221,6 @@ class _AppDataPageState extends State<AppDataPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showRestartDialog() {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
barrierDismissible: false,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
|
||||||
title: Row(
|
|
||||||
children: [
|
|
||||||
Icon(Icons.refresh, color: AppConstants.primaryColor),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
const Text('需要重启'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
content: const Text('数据已清空,需要重启应用才能生效。'),
|
|
||||||
actions: [
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: AppConstants.primaryColor,
|
|
||||||
foregroundColor: Colors.white,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: const Text('知道了'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showSnackBar(String message) {
|
void _showSnackBar(String message) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
|
|||||||
@@ -161,30 +161,6 @@ class _SpGuidePageState extends State<SpGuidePage>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _skipToEnd() {
|
|
||||||
if (_currentPage == 1) {
|
|
||||||
if (!_agreementAccepted) {
|
|
||||||
_showNeedAcceptAgreementDialog();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_currentPage == 2) {
|
|
||||||
if (!_agreementAccepted) {
|
|
||||||
_showNeedAcceptAgreementDialog();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_pageController.hasClients) {
|
|
||||||
_pageController.animateToPage(
|
|
||||||
_totalPages - 1,
|
|
||||||
duration: const Duration(milliseconds: 500),
|
|
||||||
curve: Curves.easeInOut,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showNeedAcceptAgreementDialog() {
|
void _showNeedAcceptAgreementDialog() {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import '../../constants/app_constants.dart';
|
import '../../constants/app_constants.dart';
|
||||||
import '../../controllers/history_controller.dart';
|
import '../../controllers/history_controller.dart';
|
||||||
import '../../utils/flutter_compatibility_fix.dart';
|
|
||||||
|
|
||||||
class HistoryPage extends StatefulWidget {
|
class HistoryPage extends StatefulWidget {
|
||||||
const HistoryPage({super.key});
|
const HistoryPage({super.key});
|
||||||
@@ -363,7 +362,7 @@ class _HistoryPageState extends State<HistoryPage> {
|
|||||||
}).toList(),
|
}).toList(),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
_sortHistory(_sortTypes.indexOf(value!));
|
_sortHistory(_sortTypes.indexOf(value));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
import '../../../constants/app_constants.dart';
|
import '../../../constants/app_constants.dart';
|
||||||
import '../../../controllers/sqlite_storage_controller.dart';
|
import '../../../controllers/shared_preferences_storage_controller.dart';
|
||||||
import '../../../controllers/history_controller.dart';
|
import '../../../controllers/history_controller.dart';
|
||||||
import '../../../services/network_listener_service.dart';
|
import '../../../services/network_listener_service.dart';
|
||||||
|
|
||||||
@@ -47,7 +47,8 @@ class _DistinguishPageState extends State<DistinguishPage> {
|
|||||||
Future<void> _loadAnswerRecords() async {
|
Future<void> _loadAnswerRecords() async {
|
||||||
try {
|
try {
|
||||||
// 获取答题记录列表
|
// 获取答题记录列表
|
||||||
List<String> records = await SQLiteStorageController.getStringList(
|
List<String> records =
|
||||||
|
await SharedPreferencesStorageController.getStringList(
|
||||||
'poetryAnswerRecords',
|
'poetryAnswerRecords',
|
||||||
defaultValue: [],
|
defaultValue: [],
|
||||||
);
|
);
|
||||||
@@ -85,27 +86,27 @@ class _DistinguishPageState extends State<DistinguishPage> {
|
|||||||
/// 加载统计数据
|
/// 加载统计数据
|
||||||
Future<void> _loadStatistics() async {
|
Future<void> _loadStatistics() async {
|
||||||
try {
|
try {
|
||||||
_totalQuestions = await SQLiteStorageController.getInt(
|
_totalQuestions = await SharedPreferencesStorageController.getInt(
|
||||||
'totalQuestions',
|
'totalQuestions',
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
);
|
);
|
||||||
_correctAnswers = await SQLiteStorageController.getInt(
|
_correctAnswers = await SharedPreferencesStorageController.getInt(
|
||||||
'correctAnswers',
|
'correctAnswers',
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
);
|
);
|
||||||
_wrongAnswers = await SQLiteStorageController.getInt(
|
_wrongAnswers = await SharedPreferencesStorageController.getInt(
|
||||||
'wrongAnswers',
|
'wrongAnswers',
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
);
|
);
|
||||||
int totalTime = await SQLiteStorageController.getInt(
|
int totalTime = await SharedPreferencesStorageController.getInt(
|
||||||
'totalTime',
|
'totalTime',
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
);
|
);
|
||||||
_hintCount = await SQLiteStorageController.getInt(
|
_hintCount = await SharedPreferencesStorageController.getInt(
|
||||||
'hintCount',
|
'hintCount',
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
);
|
);
|
||||||
_skipCount = await SQLiteStorageController.getInt(
|
_skipCount = await SharedPreferencesStorageController.getInt(
|
||||||
'skipCount',
|
'skipCount',
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
);
|
);
|
||||||
@@ -453,7 +454,10 @@ $_poetryLevel
|
|||||||
|
|
||||||
if (confirmed == true) {
|
if (confirmed == true) {
|
||||||
try {
|
try {
|
||||||
await SQLiteStorageController.setStringList('poetryAnswerRecords', []);
|
await SharedPreferencesStorageController.setStringList(
|
||||||
|
'poetryAnswerRecords',
|
||||||
|
[],
|
||||||
|
);
|
||||||
setState(() {
|
setState(() {
|
||||||
_answerRecords = [];
|
_answerRecords = [];
|
||||||
});
|
});
|
||||||
@@ -810,87 +814,4 @@ $_poetryLevel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从答题记录创建笔记
|
|
||||||
Future<void> _createNoteFromRecords() async {
|
|
||||||
try {
|
|
||||||
// 生成答题记录的详细内容
|
|
||||||
final StringBuffer content = StringBuffer();
|
|
||||||
content.writeln('## 答题记录汇总');
|
|
||||||
content.writeln(
|
|
||||||
'生成时间: ${DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now())}',
|
|
||||||
);
|
|
||||||
content.writeln('总记录数: ${_answerRecords.length}');
|
|
||||||
content.writeln('');
|
|
||||||
|
|
||||||
// 统计信息
|
|
||||||
int correctCount = 0;
|
|
||||||
int totalCount = _answerRecords.length;
|
|
||||||
|
|
||||||
for (final record in _answerRecords) {
|
|
||||||
if (record['isCorrect'] == true) {
|
|
||||||
correctCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
content.writeln('### 统计信息');
|
|
||||||
content.writeln('- 总题数: $totalCount');
|
|
||||||
content.writeln('- 答对数: $correctCount');
|
|
||||||
content.writeln('- 答错数: ${totalCount - correctCount}');
|
|
||||||
content.writeln(
|
|
||||||
'- 正确率: ${totalCount > 0 ? (correctCount / totalCount * 100).toStringAsFixed(1) : 0}%',
|
|
||||||
);
|
|
||||||
content.writeln('');
|
|
||||||
|
|
||||||
content.writeln('### 详细记录');
|
|
||||||
content.writeln('');
|
|
||||||
|
|
||||||
for (int i = 0; i < _answerRecords.length; i++) {
|
|
||||||
final record = _answerRecords[i];
|
|
||||||
final question = record['question'] ?? '未知题目';
|
|
||||||
final userAnswer = record['userAnswer'] ?? '未知答案';
|
|
||||||
final correctAnswer = record['correctAnswer'] ?? '未知答案';
|
|
||||||
final isCorrect = record['isCorrect'] == true;
|
|
||||||
final answerTime = record['answerTime'] ?? '未知时间';
|
|
||||||
final tags = record['tags'] as List<dynamic>? ?? [];
|
|
||||||
|
|
||||||
content.writeln('#### ${i + 1}. $question');
|
|
||||||
content.writeln('- **你的答案**: $userAnswer');
|
|
||||||
content.writeln('- **正确答案**: $correctAnswer');
|
|
||||||
content.writeln('- **答题结果**: ${isCorrect ? '✅ 正确' : '❌ 错误'}');
|
|
||||||
content.writeln('- **答题时间**: ${_formatTime(answerTime)}');
|
|
||||||
|
|
||||||
if (tags.isNotEmpty) {
|
|
||||||
content.writeln('- **标签**: ${tags.join(', ')}');
|
|
||||||
}
|
|
||||||
|
|
||||||
content.writeln('');
|
|
||||||
}
|
|
||||||
|
|
||||||
final noteId = await HistoryController.saveNote(
|
|
||||||
title: '答题记录_${DateFormat('yyyyMMdd_HHmmss').format(DateTime.now())}',
|
|
||||||
content: content.toString(),
|
|
||||||
category: '答题记录',
|
|
||||||
);
|
|
||||||
|
|
||||||
if (noteId != null) {
|
|
||||||
NetworkListenerService().sendSuccessEvent(
|
|
||||||
NetworkEventType.noteUpdate,
|
|
||||||
data: noteId,
|
|
||||||
);
|
|
||||||
if (mounted) {
|
|
||||||
ScaffoldMessenger.of(
|
|
||||||
context,
|
|
||||||
).showSnackBar(const SnackBar(content: Text('答题记录已保存到笔记')));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('创建笔记失败: $e');
|
|
||||||
if (mounted) {
|
|
||||||
ScaffoldMessenger.of(
|
|
||||||
context,
|
|
||||||
).showSnackBar(SnackBar(content: Text('创建笔记失败: $e')));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import 'dart:convert';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../../constants/app_constants.dart';
|
import '../../../constants/app_constants.dart';
|
||||||
import '../../../controllers/sqlite_storage_controller.dart';
|
import '../../../controllers/shared_preferences_storage_controller.dart';
|
||||||
import 'level-jilu.dart';
|
import 'level-jilu.dart';
|
||||||
import 'flow-anim.dart';
|
import 'flow-anim.dart';
|
||||||
import 'distinguish.dart';
|
import 'distinguish.dart';
|
||||||
@@ -329,12 +329,21 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
|
|||||||
Future<void> _saveAnswerRecord({bool isCorrect = false}) async {
|
Future<void> _saveAnswerRecord({bool isCorrect = false}) async {
|
||||||
try {
|
try {
|
||||||
// 保存统计数据
|
// 保存统计数据
|
||||||
await SQLiteStorageController.setInt('totalQuestions', _totalQuestions);
|
await SharedPreferencesStorageController.setInt(
|
||||||
await SQLiteStorageController.setInt('correctAnswers', _correctAnswers);
|
'totalQuestions',
|
||||||
await SQLiteStorageController.setInt('wrongAnswers', _wrongAnswers);
|
_totalQuestions,
|
||||||
await SQLiteStorageController.setInt('totalTime', _totalTime);
|
);
|
||||||
await SQLiteStorageController.setInt('hintCount', _hintCount);
|
await SharedPreferencesStorageController.setInt(
|
||||||
await SQLiteStorageController.setInt('skipCount', _skipCount);
|
'correctAnswers',
|
||||||
|
_correctAnswers,
|
||||||
|
);
|
||||||
|
await SharedPreferencesStorageController.setInt(
|
||||||
|
'wrongAnswers',
|
||||||
|
_wrongAnswers,
|
||||||
|
);
|
||||||
|
await SharedPreferencesStorageController.setInt('totalTime', _totalTime);
|
||||||
|
await SharedPreferencesStorageController.setInt('hintCount', _hintCount);
|
||||||
|
await SharedPreferencesStorageController.setInt('skipCount', _skipCount);
|
||||||
|
|
||||||
// 保存当前题目的详细记录
|
// 保存当前题目的详细记录
|
||||||
if (_currentQuestion != null) {
|
if (_currentQuestion != null) {
|
||||||
@@ -360,7 +369,8 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 获取已有的记录列表
|
// 获取已有的记录列表
|
||||||
List<String> records = await SQLiteStorageController.getStringList(
|
List<String> records =
|
||||||
|
await SharedPreferencesStorageController.getStringList(
|
||||||
'poetryAnswerRecords',
|
'poetryAnswerRecords',
|
||||||
defaultValue: [],
|
defaultValue: [],
|
||||||
);
|
);
|
||||||
@@ -369,7 +379,7 @@ class _PoetryLevelPageState extends State<PoetryLevelPage>
|
|||||||
records.add(jsonEncode(record));
|
records.add(jsonEncode(record));
|
||||||
|
|
||||||
// 保存更新后的列表
|
// 保存更新后的列表
|
||||||
await SQLiteStorageController.setStringList(
|
await SharedPreferencesStorageController.setStringList(
|
||||||
'poetryAnswerRecords',
|
'poetryAnswerRecords',
|
||||||
records,
|
records,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,16 +4,13 @@
|
|||||||
/// 最新变化: 重新设计布局,实现朋友圈风格的个人页面
|
/// 最新变化: 重新设计布局,实现朋友圈风格的个人页面
|
||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:ui';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
|
|
||||||
import '../../constants/app_constants.dart';
|
import '../../constants/app_constants.dart';
|
||||||
import '../../controllers/history_controller.dart';
|
import '../../controllers/history_controller.dart';
|
||||||
import '../../controllers/sqlite_storage_controller.dart';
|
import '../../controllers/shared_preferences_storage_controller.dart';
|
||||||
import '../../utils/flutter_compatibility_fix.dart';
|
|
||||||
import 'history_page.dart';
|
import 'history_page.dart';
|
||||||
import 'per_card.dart';
|
import 'per_card.dart';
|
||||||
import 'settings/app_fun.dart';
|
import 'settings/app_fun.dart';
|
||||||
@@ -23,7 +20,6 @@ import 'settings/privacy.dart';
|
|||||||
import 'settings/learn-us.dart';
|
import 'settings/learn-us.dart';
|
||||||
import 'app-info.dart';
|
import 'app-info.dart';
|
||||||
import 'level/poetry.dart';
|
import 'level/poetry.dart';
|
||||||
import 'guide/sp-guide.dart';
|
|
||||||
import 'guide/permission.dart';
|
import 'guide/permission.dart';
|
||||||
import 'guide/app-data.dart';
|
import 'guide/app-data.dart';
|
||||||
import 'theme/app-diy.dart';
|
import 'theme/app-diy.dart';
|
||||||
@@ -47,10 +43,8 @@ class _ProfilePageState extends State<ProfilePage>
|
|||||||
double _startY = 0.0;
|
double _startY = 0.0;
|
||||||
// 历史记录相关
|
// 历史记录相关
|
||||||
List<Map<String, dynamic>> _poetryHistory = [];
|
List<Map<String, dynamic>> _poetryHistory = [];
|
||||||
final String _historyKey = 'poetry_history';
|
|
||||||
|
|
||||||
// 答题统计数据
|
// 答题统计数据
|
||||||
int _totalQuestions = 0;
|
|
||||||
int _correctAnswers = 0;
|
int _correctAnswers = 0;
|
||||||
int _todayQuestions = 0;
|
int _todayQuestions = 0;
|
||||||
int _weekQuestions = 0;
|
int _weekQuestions = 0;
|
||||||
@@ -86,10 +80,6 @@ class _ProfilePageState extends State<ProfilePage>
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleScroll() {
|
|
||||||
// 这个方法现在由手势检测处理
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onPageChanged(int page) {
|
void _onPageChanged(int page) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_currentPage = page;
|
_currentPage = page;
|
||||||
@@ -107,52 +97,18 @@ class _ProfilePageState extends State<ProfilePage>
|
|||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _savePoetryToHistory(Map<String, dynamic> poetryData) async {
|
|
||||||
try {
|
|
||||||
final success = await HistoryController.addToHistory(poetryData);
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
_showSnackBar('已添加到历史记录');
|
|
||||||
} else {
|
|
||||||
_showSnackBar('该诗词已在历史记录中');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
_showSnackBar('保存失败');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _clearPoetryHistory() async {
|
|
||||||
try {
|
|
||||||
final success = await HistoryController.clearHistory();
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
setState(() {
|
|
||||||
_poetryHistory.clear();
|
|
||||||
});
|
|
||||||
_showSnackBar('历史记录已清空');
|
|
||||||
} else {
|
|
||||||
_showSnackBar('清空失败');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
_showSnackBar('清空失败');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// === 答题统计相关方法 ===
|
// === 答题统计相关方法 ===
|
||||||
Future<void> _loadPoetryStatistics() async {
|
Future<void> _loadPoetryStatistics() async {
|
||||||
try {
|
try {
|
||||||
// 加载总体统计
|
// 加载总体统计
|
||||||
_totalQuestions = await SQLiteStorageController.getInt(
|
_correctAnswers = await SharedPreferencesStorageController.getInt(
|
||||||
'totalQuestions',
|
|
||||||
defaultValue: 0,
|
|
||||||
);
|
|
||||||
_correctAnswers = await SQLiteStorageController.getInt(
|
|
||||||
'correctAnswers',
|
'correctAnswers',
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
// 加载答题记录列表来计算今日和本周答题数
|
// 加载答题记录列表来计算今日和本周答题数
|
||||||
List<String> records = await SQLiteStorageController.getStringList(
|
List<String> records =
|
||||||
|
await SharedPreferencesStorageController.getStringList(
|
||||||
'poetryAnswerRecords',
|
'poetryAnswerRecords',
|
||||||
defaultValue: [],
|
defaultValue: [],
|
||||||
);
|
);
|
||||||
@@ -287,158 +243,6 @@ class _ProfilePageState extends State<ProfilePage>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildStatCard(String label, String value, IconData icon) {
|
|
||||||
// === 单个统计卡片:显示统计数据和图标 ===
|
|
||||||
return Expanded(
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.all(12),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.black.withValues(alpha: 0.05),
|
|
||||||
blurRadius: 5,
|
|
||||||
offset: const Offset(0, 1),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Icon(icon, color: AppConstants.primaryColor, size: 24),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
Text(
|
|
||||||
value,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Colors.black87,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 4),
|
|
||||||
Text(
|
|
||||||
label,
|
|
||||||
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildTabBar() {
|
|
||||||
// === 页面切换标签栏:显示当前页面指示器 ===
|
|
||||||
return GestureDetector(
|
|
||||||
behavior: HitTestBehavior.opaque,
|
|
||||||
onVerticalDragStart: (_) {},
|
|
||||||
onVerticalDragUpdate: (_) {},
|
|
||||||
onVerticalDragEnd: (_) {},
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
gradient: LinearGradient(
|
|
||||||
colors: [
|
|
||||||
AppConstants.primaryColor.withValues(alpha: 0.85),
|
|
||||||
AppConstants.primaryColor.withValues(alpha: 0.8),
|
|
||||||
],
|
|
||||||
begin: Alignment.topCenter,
|
|
||||||
end: Alignment.bottomCenter,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
// 页面指示器
|
|
||||||
Expanded(
|
|
||||||
child: Container(
|
|
||||||
height: 3,
|
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 20),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white.withValues(alpha: 0.3),
|
|
||||||
borderRadius: BorderRadius.circular(2),
|
|
||||||
),
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
|
||||||
// 背景条
|
|
||||||
Container(
|
|
||||||
height: 3,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white.withValues(alpha: 0.3),
|
|
||||||
borderRadius: BorderRadius.circular(2),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// 滑动指示器
|
|
||||||
AnimatedContainer(
|
|
||||||
duration: const Duration(milliseconds: 300),
|
|
||||||
width: MediaQuery.of(context).size.width / 3 - 40,
|
|
||||||
height: 3,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white,
|
|
||||||
borderRadius: BorderRadius.circular(2),
|
|
||||||
),
|
|
||||||
margin: EdgeInsets.only(
|
|
||||||
left:
|
|
||||||
(MediaQuery.of(context).size.width / 3 - 40) *
|
|
||||||
_currentPage,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// 页面标签
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.black.withValues(alpha: 0.1),
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
_buildTabLabel(0, '卡片'),
|
|
||||||
_buildTabLabel(1, '设置'),
|
|
||||||
_buildTabLabel(2, '更多'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildTabLabel(int index, String label) {
|
|
||||||
// === 单个页面标签:可点击切换到对应页面 ===
|
|
||||||
final isSelected = _currentPage == index;
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
// 添加 mounted 和 hasClients 检查,避免 dispose 后调用导致黑屏
|
|
||||||
if (mounted && _pageController.hasClients) {
|
|
||||||
_pageController.animateToPage(
|
|
||||||
index,
|
|
||||||
duration: const Duration(milliseconds: 300),
|
|
||||||
curve: Curves.easeInOut,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
|
||||||
child: Text(
|
|
||||||
label,
|
|
||||||
style: TextStyle(
|
|
||||||
color: isSelected ? Colors.white : Colors.white70,
|
|
||||||
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
|
|
||||||
fontSize: 14,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildPage1() {
|
Widget _buildPage1() {
|
||||||
// === 第1页:个人信息卡片展示 ===
|
// === 第1页:个人信息卡片展示 ===
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
@@ -914,15 +718,6 @@ class _ProfilePageState extends State<ProfilePage>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _navigateToSpGuidePage() {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const SpGuidePage(fromSettings: true),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _navigateToPermissionPage() {
|
void _navigateToPermissionPage() {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
@@ -972,129 +767,7 @@ class _ProfilePageState extends State<ProfilePage>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// === 历史记录对话框 ===
|
void _showMoreOptions() {
|
||||||
void _showHistoryDialog() {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => Dialog(
|
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
|
|
||||||
child: Container(
|
|
||||||
width: MediaQuery.of(context).size.width * 0.9,
|
|
||||||
height: MediaQuery.of(context).size.height * 0.7,
|
|
||||||
padding: const EdgeInsets.all(20),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
// 对话框标题
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'历史记录',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: AppConstants.primaryColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: _poetryHistory.isEmpty
|
|
||||||
? null
|
|
||||||
: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
_clearPoetryHistory();
|
|
||||||
},
|
|
||||||
child: const Text('清空'),
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
icon: const Icon(Icons.close),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
// 历史记录列表
|
|
||||||
Expanded(
|
|
||||||
child: _poetryHistory.isEmpty
|
|
||||||
? Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.history,
|
|
||||||
size: 64,
|
|
||||||
color: Colors.grey[400],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
Text(
|
|
||||||
'暂无历史记录',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
color: Colors.grey[600],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: ListView.builder(
|
|
||||||
itemCount: _poetryHistory.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final poetry = _poetryHistory[index];
|
|
||||||
return Card(
|
|
||||||
margin: const EdgeInsets.only(bottom: 8),
|
|
||||||
child: ListTile(
|
|
||||||
leading: CircleAvatar(
|
|
||||||
radius: 20,
|
|
||||||
backgroundColor: AppConstants.primaryColor
|
|
||||||
.withValues(alpha: 0.1),
|
|
||||||
child: Text(
|
|
||||||
'${index + 1}',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: AppConstants.primaryColor,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
poetry['name'] ?? '未知诗词',
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
maxLines: 2,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
subtitle: Text(
|
|
||||||
'${poetry['alias'] ?? '未知朝代'} • ${poetry['date'] ?? ''}',
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: Colors.grey,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
trailing: IconButton(
|
|
||||||
icon: const Icon(Icons.favorite_border),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
_showSnackBar('已添加到收藏');
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget? _showMoreOptions() {
|
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
|
|||||||
@@ -25,9 +25,7 @@ class _AppFunSettingsPageState extends State<AppFunSettingsPage> {
|
|||||||
bool _vibrationEnabled = true;
|
bool _vibrationEnabled = true;
|
||||||
bool _darkModeEnabled = false;
|
bool _darkModeEnabled = false;
|
||||||
bool _preloadEnabled = true;
|
bool _preloadEnabled = true;
|
||||||
bool _notificationEnabled = true;
|
|
||||||
bool _globalTipsEnabled = true; // 添加全局Tips开关状态
|
bool _globalTipsEnabled = true; // 添加全局Tips开关状态
|
||||||
int _cacheSize = 128;
|
|
||||||
|
|
||||||
static const String _autoRefreshKey = 'auto_refresh_enabled';
|
static const String _autoRefreshKey = 'auto_refresh_enabled';
|
||||||
static const String _debugInfoKey = 'debug_info_enabled';
|
static const String _debugInfoKey = 'debug_info_enabled';
|
||||||
@@ -311,28 +309,6 @@ class _AppFunSettingsPageState extends State<AppFunSettingsPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildCacheItem() {
|
|
||||||
return ListTile(
|
|
||||||
leading: Container(
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: AppConstants.primaryColor.withValues(alpha: 0.1),
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
child: Icon(Icons.storage, color: AppConstants.primaryColor, size: 20),
|
|
||||||
),
|
|
||||||
title: const Text(
|
|
||||||
'缓存大小',
|
|
||||||
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500),
|
|
||||||
),
|
|
||||||
subtitle: Text(
|
|
||||||
'$_cacheSize MB',
|
|
||||||
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
|
|
||||||
),
|
|
||||||
trailing: Icon(Icons.chevron_right, color: Colors.grey[400]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildActionItem(
|
Widget _buildActionItem(
|
||||||
String title,
|
String title,
|
||||||
String subtitle,
|
String subtitle,
|
||||||
@@ -403,32 +379,6 @@ class _AppFunSettingsPageState extends State<AppFunSettingsPage> {
|
|||||||
).showSnackBar(SnackBar(content: Text(message)));
|
).showSnackBar(SnackBar(content: Text(message)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showClearCacheDialog() {
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: const Text('清除缓存'),
|
|
||||||
content: const Text('确定要清除所有缓存数据吗?这不会影响您的笔记和收藏。'),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
child: const Text('取消'),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
setState(() {
|
|
||||||
_cacheSize = 0;
|
|
||||||
});
|
|
||||||
_showSnackBar('缓存已清除');
|
|
||||||
},
|
|
||||||
child: Text('确定', style: TextStyle(color: Colors.red[400])),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showResetDialog() {
|
void _showResetDialog() {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@@ -450,7 +400,6 @@ class _AppFunSettingsPageState extends State<AppFunSettingsPage> {
|
|||||||
_vibrationEnabled = true;
|
_vibrationEnabled = true;
|
||||||
_globalTipsEnabled = true; // 重置全局Tips开关为开启
|
_globalTipsEnabled = true; // 重置全局Tips开关为开启
|
||||||
_darkModeEnabled = false;
|
_darkModeEnabled = false;
|
||||||
_notificationEnabled = true;
|
|
||||||
});
|
});
|
||||||
_showSnackBar('已恢复默认设置');
|
_showSnackBar('已恢复默认设置');
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user