From 7872f2e78a541c3deac20558080c046e69059e4d Mon Sep 17 00:00:00 2001 From: Developer Date: Thu, 2 Apr 2026 22:30:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=B3=E6=80=80=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 440 ++-------- .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 9122 -> 9542 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 4699 -> 4862 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 30020 -> 33477 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 14642 -> 15599 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 52122 -> 59415 bytes lib/config/app_config.dart | 2 +- lib/controllers/settings/suggestions.dart | 178 ++++ lib/main.dart | 32 +- lib/models/colors/app_colors.dart | 87 ++ lib/models/colors/theme_colors.dart | 51 ++ .../level => services/document}/api.md | 0 lib/services/get/care_controller.dart | 87 ++ lib/services/get/favorites_controller.dart | 57 +- lib/services/get/theme_controller.dart | 47 +- lib/views/active/active_search_page.dart | 16 +- lib/views/active/category_page.dart | 35 +- lib/views/active/popular_page.dart | 243 +++-- lib/views/active/rate.dart | 30 +- lib/views/active/tags/corr_page.dart | 29 +- lib/views/discover_page.dart | 12 +- lib/views/favorites_page.dart | 40 +- lib/views/footprint/all_list.dart | 37 +- lib/views/footprint/collect_notes.dart | 94 +- lib/views/footprint/footprint_page.dart | 78 +- lib/views/footprint/liked_poetry_manager.dart | 94 +- lib/views/footprint/local_jilu.dart | 23 +- lib/views/home/care/care-page.dart | 478 ++++++++++ lib/views/home/care/care_poetry_page.dart | 512 +++++++++++ lib/views/home/care/care_widgets.dart | 171 ++++ lib/views/home/care/pinyin_helper.dart | 79 ++ lib/views/home/home_page.dart | 71 +- lib/views/home/home_part.dart | 100 +-- lib/views/home/set/home_components.dart | 31 +- lib/views/profile/app-info.dart | 128 +-- .../profile/components/bug_list_page.dart | 145 ++- lib/views/profile/components/entire_page.dart | 135 ++- .../components/login_register_dialog.dart | 177 ++-- lib/views/profile/components/pop-menu.dart | 19 +- .../components/server_info_dialog.dart | 443 +++++----- lib/views/profile/expand/manu-script.dart | 253 ++++-- lib/views/profile/expand/tougao.dart | 10 +- lib/views/profile/expand/vote.dart | 36 +- lib/views/profile/guide/app-data.dart | 19 +- lib/views/profile/guide/beginner_page.dart | 35 +- lib/views/profile/guide/permission.dart | 86 +- lib/views/profile/guide/sp-guide.dart | 116 +-- lib/views/profile/history_page.dart | 48 +- lib/views/profile/level/distinguish.dart | 827 +++++++++--------- lib/views/profile/level/flow-anim.dart | 39 +- lib/views/profile/level/poetry.dart | 541 +++++------- lib/views/profile/per_card.dart | 26 +- lib/views/profile/profile_page.dart | 342 +++++--- lib/views/profile/settings/app_fun.dart | 122 +-- lib/views/profile/settings/learn-us.dart | 106 +-- lib/views/profile/settings/offline-data.dart | 67 +- lib/views/profile/settings/privacy.dart | 28 +- lib/views/profile/settings/user-plan.dart | 41 +- lib/views/profile/settings/widgets.dart | 36 +- lib/views/profile/theme/app-diy.dart | 247 ++++-- lib/views/responsive_home_page.dart | 23 +- lib/widgets/care/care_mode_navigation.dart | 219 +++++ lib/widgets/common_widgets.dart | 12 +- lib/widgets/main_navigation.dart | 85 +- lib/widgets/responsive_widgets.dart | 6 +- lib/widgets/tabbed_nav_app_bar.dart | 8 +- lib/widgets/tap-liquid-glass.dart | 6 +- pubspec.lock | 8 + pubspec.yaml | 3 +- update_android_icons.py | 40 + 70 files changed, 4884 insertions(+), 2752 deletions(-) create mode 100644 lib/controllers/settings/suggestions.dart create mode 100644 lib/models/colors/app_colors.dart create mode 100644 lib/models/colors/theme_colors.dart rename lib/{views/profile/level => services/document}/api.md (100%) create mode 100644 lib/services/get/care_controller.dart create mode 100644 lib/views/home/care/care-page.dart create mode 100644 lib/views/home/care/care_poetry_page.dart create mode 100644 lib/views/home/care/care_widgets.dart create mode 100644 lib/views/home/care/pinyin_helper.dart create mode 100644 lib/widgets/care/care_mode_navigation.dart create mode 100644 update_android_icons.py diff --git a/CHANGELOG.md b/CHANGELOG.md index efd2614..b5ddb5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,72 @@ All notable changes to this project will be documented in this file. --- +## [1.3.37] - 2026-04-02 + +### 新增 +- ✨ **主题颜色选择器重新设计** + - 新增中国传统色彩:书褐色(#8B4513)和宣纸色(#F5F5F0) + - 颜色选择器改为横向滚动列表,每个颜色显示圆形色块和中文名称 + - 选中状态显示勾选图标和发光阴影效果 + - 颜色名称采用中国风命名:紫韵、天蓝、翠绿、橙光、朱红、青碧、书褐、明黄、桃粉、湖青、罗兰、宣纸 + - 涉及文件: + - `lib/models/colors/theme_colors.dart` - 新增中国传统色彩 + - `lib/views/profile/theme/app-diy.dart` - 重新设计颜色选择器 + +## [1.3.36] - 2026-04-02 + +### 新增 +- ✨ **Profile 组件主题色支持** + - Bug列表页面、全站统计页面、投票凭证弹窗、Pop菜单、服务器信息弹窗支持主题色设置 + - 所有组件颜色动态响应主题色变化,包括按钮、卡片、图标、文本等 + - 新增 `AppColors` 类统一管理动态主题色,支持深色/浅色模式自动切换 + - 使用 iOS 风格系统颜色(蓝、绿、红、橙、紫等)保持一致性 + - 涉及文件: + - `lib/models/colors/app_colors.dart` - 新建动态颜色管理类 + - `lib/views/profile/components/bug_list_page.dart` - 支持主题色 + - `lib/views/profile/components/entire_page.dart` - 支持主题色 + - `lib/views/profile/components/login_register_dialog.dart` - 支持主题色 + - `lib/views/profile/components/pop-menu.dart` - 支持主题色 + - `lib/views/profile/components/server_info_dialog.dart` - 支持主题色 + - `lib/views/profile/level/distinguish.dart` - 支持主题色 + - `lib/views/profile/level/flow-anim.dart` - 支持主题色 + - `lib/views/profile/level/poetry.dart` - 支持主题色 + - `lib/views/profile/app-info.dart` - 支持主题色 + +## [1.3.35] - 2026-04-02 + +### 新增 +- ✨ **活跃页面主题色支持** + - 搜索页面、热门页面、分类页面、活跃度页面支持主题色设置 + - 所有组件颜色动态响应主题色变化,包括Tab栏、按钮、卡片边框等 + - 涉及文件: + - `lib/views/active/active_search_page.dart` - 支持主题色 + - `lib/views/active/popular_page.dart` - 支持主题色 + - `lib/views/active/category_page.dart` - 支持主题色 + - `lib/views/active/rate.dart` - 支持主题色 + +## [1.3.34] - 2026-04-02 + +### 新增 +- ✨ **多页面主题色支持** + - 发现页面、标签页面、收藏页面、响应式首页等多个页面支持主题色设置 + - 所有组件颜色动态响应主题色变化 + - 涉及文件: + - `lib/views/active/tags/corr_page.dart` - 支持主题色 + - `lib/views/discover_page.dart` - 支持主题色 + - `lib/views/favorites_page.dart` - 支持主题色 + - `lib/views/responsive_home_page.dart` - 支持主题色 + +## [1.3.33] - 2026-04-02 + +### 新增 +- ✨ **首页主题色支持** + - 首页诗词卡片、按钮、加载状态等组件支持主题色设置 + - 主题色变化时,首页所有相关组件会实时更新 + - 涉及文件: + - `lib/views/home/home_part.dart` - 支持主题色 + - `lib/views/home/set/home_components.dart` - 支持主题色 + ## [1.3.32] - 2026-04-02 ### 新增 @@ -16,8 +82,6 @@ All notable changes to this project will be documented in this file. - 涉及文件: - `lib/views/profile/per_card.dart` - 添加头像切换功能 ---- - ## [1.3.31] - 2026-04-02 ### 优化 @@ -30,374 +94,6 @@ All notable changes to this project will be documented in this file. --- -## [1.3.30] - 2026-04-02 - -### 新增 -- ⭐ **添加全局 Tips 开关管理器** - - 创建 `GlobalTipsManager` 单例类,支持 ValueNotifier 状态监听 - - 修改设置页面,全局 Tips 开关使用 GlobalTipsManager 管理 - - 修改发现页面,使用 ValueListenableBuilder 监听状态变化 - - 开关关闭后,发现页面的 Tips 提示会立即隐藏,下方布局自动向上占位 - - 涉及文件: - - `lib/views/home/home-load.dart` - 添加 GlobalTipsManager - - `lib/views/profile/settings/app_fun.dart` - 使用 GlobalTipsManager - - `lib/views/discover_page.dart` - 使用 ValueListenableBuilder 监听状态 - -### 优化 -- 🎨 **给诗词原文添加轻微背景色** - - 给诗词原文区域添加主题色 20% 透明度的背景 - - 添加"诗词原文"标题,使区域更清晰 - - 涉及文件: - - `lib/views/home/home_part.dart` - 添加背景色和标题 - ---- - -## [1.3.29] - 2026-04-02 - -### 修复 -- 🐛 **修复调试信息开关关闭后仍显示调试信息的问题** - - 修改 `home_controller.dart`,将所有 `Get.snackbar` 调用改为通过 `DebugInfoManager` 显示 - - 调试信息现在完全受设置页面中的"调试信息"开关控制 - - 开关关闭后,所有调试提示(刷新、下一条、上一条、点赞、复制等)都不会显示 - - 涉及文件: - - `lib/services/get/home_controller.dart` - 统一通过 DebugInfoManager 显示调试信息 - ---- - -## [1.3.28] - 2026-04-02 - -### 优化 -- 🚀 **优化设置页面,内外实时生效** - - 修改 `DebugInfoManager`,添加 `ValueNotifier` 支持实时状态监听 - - 修改 `AutoRefreshManager`,添加 `ValueNotifier` 支持实时状态监听,init 时自动启动定时器 - - 修改 `home_page.dart`,从 `StatelessWidget` 改为 `StatefulWidget`,添加 `ValueListenableBuilder` 监听次要按钮状态 - - 次要按钮(上一条、分享)的显示/隐藏现在可以实时响应设置变化 - - 涉及文件: - - `lib/views/home/home-load.dart` - 添加 ValueNotifier 支持 - - `lib/views/home/home_page.dart` - 添加实时监听次要按钮状态 - - `lib/views/profile/settings/app_fun.dart` - 已优化设置逻辑 - ---- - -## [1.3.26] - 2026-04-02 - -### 优化 -- 🎨 **优化主页悬浮按钮位置,紧贴底部导航栏** - - 修改悬浮按钮 bottom 定位值,从使用 liquidGlassTotalHeight 改为使用 liquidGlassHeight + liquidGlassBottomMargin - - 调整按钮间距,使布局更紧凑美观 - - 确保按钮固定位置,不随诗词卡片上下滚动 - - 涉及文件: - - `lib/views/home/home_page.dart` - 修改悬浮按钮定位 - ---- - -## [1.3.25] - 2026-04-02 - -### 新增 -- ✨ **新增液态玻璃导航栏透明度级别控制** - - 在 TapLiquidGlassController 中添加 TransparencyLevel 枚举 - - 支持三个透明度级别:弱、中、强 - - 弱:当前效果(白色 0.35/0.2,灰色 0.35/0.2) - - 中:中等透明度(白色 0.22/0.12,灰色 0.22/0.12) - - 强:几乎透明(白色 0.1/0.05,灰色 0.1/0.05) - - 在功能设置页面添加 3 级开关,开启 Tap 沉浸光感后显示 - - 透明度设置持久化到 SharedPreferences - - 涉及文件: - - `lib/services/get/tap_liquid_glass_controller.dart` - 新增透明度级别控制 - - `lib/views/profile/settings/app_fun.dart` - 添加透明度级别开关 - - `lib/widgets/tap-liquid-glass.dart` - 应用透明度级别 - ---- - -## [1.3.24] - 2026-04-02 - -### 修复 -- 🔧 **修复发现页 Tips 显示和关闭功能** - - 在 DiscoverController 中添加全局 tips 开关设置加载逻辑 - - 修改 discover_page.dart 显示条件,根据全局开关和本地关闭状态控制显示 - - 全局Tips关闭时,发现页不显示提示 - - 全局Tips开启时,点击X可关闭提示(仅当前会话,不写入SharedPreferences) - - 涉及文件: - - `lib/services/get/discover_controller.dart` - 添加全局tips开关加载 - - `lib/views/discover_page.dart` - 修改tips显示逻辑 - ---- - -## [1.3.23] - 2026-04-02 - -### 优化 -- 🎨 **优化 Tap 沉浸光感液态玻璃导航栏视觉效果** - - 增强透明效果,降低背景透明度约 30-40% - - 移除选中项胶囊形背景,消除两层包裹效果 - - 移除点击水波纹和高亮效果,保持纯净玻璃质感 - - 添加灰度渐变底层,提升玻璃逼真度 - - 优化图标缩放效果(从 1.12 调整为 1.1) - - 增加模糊强度(从 20 提升至 35) - - 增强阴影效果,提升悬浮感 - - 涉及文件: - - `lib/widgets/tap-liquid-glass.dart` - 优化视觉效果 - - `lib/config/app_config.dart` - 增加模糊强度 - ---- - -## [1.3.22] - 2026-04-02 - -### 重新设计 -- 🎨 **重新设计 Tap 沉浸光感液态玻璃导航栏** - - 实现 iOS 26 风格的液态玻璃效果 - - 使用 BackdropFilter 实现真正的毛玻璃模糊 - - 下层页面滑动时,能透过底栏模糊看到底部大概轮廓 - - 添加双层阴影效果,增强悬浮感 - - 使用渐变背景替代纯色,提升玻璃质感 - - 选中项添加胶囊形背景指示器 - - 优化图标动画效果,选中时放大 1.12 倍 - - 支持动画开关控制,响应主题控制器设置 - - 添加详细的使用示例和注意事项注释 - - 涉及文件: - - `lib/widgets/tap-liquid-glass.dart` - 重新设计液态玻璃导航栏 - -### 修复 -- 🔧 **修复液态玻璃导航栏布局遮挡问题** - - 使用 Stack 布局替代 Scaffold.bottomNavigationBar - - 导航栏悬浮在页面内容上方,不再遮挡下方布局 - - 页面内容延伸到屏幕底部,透过玻璃可见 - - 添加 `liquidGlassTotalHeight` 配置计算导航栏总高度 - - 修改所有子页面 ListView/ScrollView 底部内边距 - - 涉及文件: - - `lib/widgets/main_navigation.dart` - 使用 Stack 布局实现悬浮效果 - - `lib/config/app_config.dart` - 添加导航栏高度计算 - - `lib/views/home/home_page.dart` - 添加底部内边距 - - `lib/views/discover_page.dart` - 添加底部内边距 - - `lib/views/active/popular_page.dart` - 添加底部内边距 - - `lib/views/footprint/all_list.dart` - 添加底部内边距 - - `lib/views/footprint/liked_poetry_manager.dart` - 添加底部内边距 - - `lib/views/footprint/local_jilu.dart` - 添加底部内边距 - - `lib/views/profile/profile_page.dart` - 添加底部内边距 - ---- - -## [1.3.21] - 2026-04-02 - -### 优化 -- 🎨 **优化Tap沉浸光感液态玻璃导航栏** - - 恢复毛玻璃效果,去掉外层纯色背景遮挡 - - 滑动时能模糊看到下层视图的大概轮廓 - - 保持椭圆形悬浮设计和毛玻璃模糊效果 - - 优化点击区域,使用 InkWell 替代 GestureDetector - - 点击区域扩展到整个 Expanded 区域,包括空白区域 - - 添加水波纹效果,提升点击反馈 - - 涉及文件: - - `lib/widgets/tap-liquid-glass.dart` - 优化液态玻璃导航栏 - ---- - -## [1.3.20] - 2026-04-01 - -### 新增 -- ✨ **深色模式支持全面上线** - - 创建 ThemeController 管理深色模式状态 - - 使用 SharedPreferences 持久化深色模式设置 - - 全局深色模式适配,涉及 20+ 页面 - - iOS 风格的深色配色方案 - - 统一的暗色背景、卡片、文字颜色 - - 涉及文件: - - `lib/models/night-mode/theme_model.dart` - 主题数据模型 - - `lib/services/get/theme_controller.dart` - 主题控制器 - - `lib/views/profile/theme/app-diy.dart` - 深色模式开关 - - `lib/views/home/home_page.dart` - 首页深色模式 - - `lib/views/home/home_part.dart` - 首页组件 - - `lib/views/home/home-load.dart` - 首页加载 - - `lib/views/home/home_components.dart` - 首页组件 - - `lib/views/discover_page.dart` - 发现页深色模式 - - `lib/views/active/rate.dart` - 评价页深色模式 - - `lib/views/active/category_page.dart` - 分类页深色模式 - - `lib/views/active/active_search_page.dart` - 搜索页深色模式 - - `lib/views/active/tags/corr_page.dart` - 标签页深色模式 - - `lib/views/favorites_page.dart` - 收藏页深色模式 - - `lib/views/footprint/all_list.dart` - 全部列表深色模式 - - `lib/views/footprint/collect_notes.dart` - 笔记页深色模式 - - `lib/views/footprint/footprint_page.dart` - 足迹页深色模式 - - `lib/views/footprint/local_jilu.dart` - 本地记录深色模式 - - `lib/views/profile/profile_page.dart` - 个人中心深色模式 - - `lib/views/profile/history_page.dart` - 历史页深色模式 - - `lib/views/profile/app-info.dart` - 应用信息深色模式 - - `lib/views/profile/level/distinguish.dart` - 辨别页深色模式 - - `lib/views/profile/level/flow-anim.dart` - 动画页深色模式 - - `lib/views/profile/level/level-jilu.dart` - 级别记录深色模式 - - `lib/views/profile/level/poetry.dart` - 诗词页深色模式 - - `lib/views/profile/guide/beginner_page.dart` - 教程页深色模式 - - `lib/views/profile/guide/sp-guide.dart` - 引导页深色模式 - - `lib/views/profile/guide/tongji.dart` - 统计页深色模式 - - `lib/utils/app_initializer.dart` - 应用初始化 - - `lib/utils/app_theme.dart` - 应用主题 - -### 修复 -- 🔧 **修复诗词卡片加载状态问题** - - 使用 Obx 包装 PoetryCard 组件 - - 确保 sectionLoadingStates 更新时 UI 响应式刷新 - - 解决"xx加载中..."一直显示的问题 - - 涉及文件: - - `lib/views/home/home_page.dart` - 修复加载状态 - ---- - -## [1.3.19] - 2026-04-01 - -### 新增 -- ✨ **实现应用数据计算功能** - - 使用原生 dart:io 实现软件包、缓存、数据大小计算 - - 递归计算目录大小,支持多层级文件遍历 - - 字节格式化,自动转换为 B/KB/MB/GB/TB - - 软件包大小:计算应用数据目录总大小 - - 缓存大小:计算临时目录大小 - - 数据大小:计算文档和支持目录大小 - - 占用空间:显示软件包+缓存+数据+10MB 的总和 - - 实现清空缓存功能,递归删除临时文件 - - 清空后自动刷新缓存大小显示 - - 新增原生清理数据按钮,直接删除文件系统数据 - - 双重确认对话框,防止误操作 - - 原生清理完成后提示关闭应用 - - 涉及文件: - - `lib/views/profile/guide/app-data.dart` - 实现数据计算功能 - -### 修复 -- 🔧 **统一版本号显示** - - 修复 learn-us.dart 中版本号引用错误问题 - - 修复 app-info.dart 中硬编码版本号问题 - - 统一使用 AppConfig.appVersion 显示版本号 - - 涉及文件: - - `lib/views/profile/settings/learn-us.dart` - 修正版本号引用 - - `lib/views/profile/app-info.dart` - 统一版本号显示 - -### 更新 -- 🎨 **多平台应用图标全面更新** - - 使用用户提供的本地图片作为应用图标 - - 原图尺寸:647x559,自动居中裁剪为正方形 - - 新增 216x216 尺寸图标 - - 支持所有平台图标生成: - - **HarmonyOS**:完整图标集(9个尺寸) - - **Android**:启动图标(5个尺寸) - - **macOS**:应用图标(7个尺寸) - - 所有平台图标已同步更新 - - 涉及文件: - - `ohos/entry/src/main/resources/base/media/` - HarmonyOS 图标集(含 icon_216.png) - - `ohos/AppScope/resources/base/media/app_icon.png` - HarmonyOS AppScope 图标 - - `android/app/src/main/res/mipmap-*/ic_launcher.png` - Android 启动图标 - - `macos/Runner/Assets.xcassets/AppIcon.appiconset/` - macOS 图标 - - `generate_all_icons.py` - 多平台图标生成脚本 - - `assets/XZ4QCHGE][UUYGCV2G(~88J.png` - 用户提供的原始图片 - ---- - -## [1.3.18] - 2026-04-01 - -### 改进 -- ✨ **优化诗词投稿检测功能** - - 在"检测是否存在"按钮左边添加检测状态显示 - - 显示"未检测"、"已检测"、"未通过"三种状态 - - 配套图标:pending、check_circle、close - - 使用主题色和错误色区分不同状态 - - 提交前要求必须先检测且通过才能提交 - - 未检测时提示"请先检测诗词是否存在" - - 涉及文件: - - `lib/views/profile/expand/manu-script.dart` - 优化检测功能 - ---- - -## [1.3.17] - 2026-04-01 - -### 优化 -- 🎨 **重新设计使用教程页面** - - iOS 风格的全新设计,更符合苹果设计理念 - - 增加了四个主要页面的界面预览模块(首页、发现页、足迹页、个人中心) - - 每个模块使用不同的 emoji 图标和配色方案,图文并茂 - - 保留左侧进度条并优化动画效果 - - 新增页面淡入动画和卡片逐个出现动画 - - 使用主题色 AppConstants.primaryColor 统一配色 - - 圆角卡片设计,柔和阴影,符合 iOS 风格 - - 涉及文件: - - `lib/views/profile/guide/beginner_page.dart` - 重新设计使用教程页面 - -### 改进 -- 🎨 **优化进度条悬浮效果** - - 进度条改为悬浮在内容上方,不再单独占位 - - 添加渐变背景遮罩,从左到右透明度渐变 - - 内容区域宽度增加,提升阅读体验 - - 涉及文件: - - `lib/views/profile/guide/beginner_page.dart` - 优化进度条悬浮效果 -- ✨ **优化导航栏设计** - - 标题文字使用主题色 AppConstants.primaryColor - - 右上角添加帮助图标按钮 - - 点击按钮跳转到欢迎引导页 SpGuidePage - - 涉及文件: - - `lib/views/profile/guide/beginner_page.dart` - 优化导航栏 -- ✨ **添加滚动隐藏 AppBar 功能** - - 使用 SliverAppBar 实现滚动时自动隐藏效果 - - floating: true 和 snap: true 配合,实现自然收起动画 - - 向下滚动时 AppBar 自动隐藏,向上滚动时自动显示 - - 所有图标颜色统一使用主题色 AppConstants.primaryColor - - 涉及文件: - - `lib/views/profile/guide/beginner_page.dart` - 添加滚动隐藏功能 -- 🎨 **美化开发者卡片** - - 新增微信公众号信息展示 - - 公众号名称:微风暴 - - 使用微信绿色主题色 (0xFF07C160) - - 添加搜索图标和标签样式设计 - - 渐变色背景卡片,圆角设计 - - 涉及文件: - - `lib/views/profile/settings/learn-us.dart` - 美化开发者卡片 -- 🎨 **优化卡片布局** - - 去掉开发者卡片和团队信息卡片中的分割线 - - 调整内边距,使布局更紧凑美观 - - 内容区块之间使用自然间距代替分割线 - - 涉及文件: - - `lib/views/profile/settings/learn-us.dart` - 优化卡片布局 -- ✨ **增强开发者卡片功能** - - 邮箱地址字体加大,从 13 改为 15 - - 公众号"微风暴"右边添加复制图标 - - 点击复制图标可复制公众号名称到剪贴板 - - 复制成功后显示 SnackBar 提示 - - 涉及文件: - - `lib/views/profile/settings/learn-us.dart` - 增强开发者卡片 -- 🎨 **优化设备信息卡片布局** - - 设备信息从 1×6 列表布局改为 2×3 网格布局 - - 新增网格布局信息项 widget,带卡片样式 - - 使用主题色 AppConstants.primaryColor 统一图标颜色 - - 可复制项带复制图标,点击可复制 - - 卡片样式:灰色背景,圆角边框,更美观 - - 去掉设备信息和设备详细信息之间的空白区域 - - 涉及文件: - - `lib/views/profile/app-info.dart` - 优化设备信息布局 - ---- - -## [1.3.16] - 2026-04-01 - -### 新增 -- ✨ **新增使用教程页面** - - 创建 iOS 风格的使用教程页面 `BeginnerPage` - - 超长列表布局,包含 16 个功能模块 - - 左侧悬浮进度指示器,带平滑动画 - - 显示当前阅读进度百分比 - - 主题色设计,圆角卡片,阴影效果 - - 功能模块:首页功能、发现页面、足迹页面、个人中心、诗词阅读、收藏功能、搜索功能、答题挑战、离线模式、个性化设置、投稿功能、投票功能、天气与十二时辰、图片分享、数据管理、帮助与反馈 - - 涉及文件: - - `lib/views/profile/guide/beginner_page.dart` - 新建使用教程页面 - - `lib/views/profile/components/pop-menu.dart` - 修改按钮跳转 - ---- - -## [1.3.15] - 2026-04-01 - -### 修改 -- 🎨 **修改收藏页面标题** - - 将收藏页面 AppBar 标题从"收藏"改为"足迹" - - 底部导航栏标签保持"收藏"不变 - - 涉及文件: - - `lib/views/favorites_page.dart` - 修改页面标题 - ---- - ## 软件特性功能 ### 已开发完成 @@ -416,6 +112,9 @@ All notable changes to this project will be documented in this file. - ✅ 全站统计页面 - ✅ 修复 AppBar 标题显示问题 - ✅ 个人卡片emoji头像切换功能 +- ✅ 深色模式支持 +- ✅ 液态玻璃导航栏 +- ✅ 多页面主题色支持 ### 开发中 - 🚧 更多功能优化 @@ -428,5 +127,6 @@ All notable changes to this project will be documented in this file. | 投稿功能优化 | 2 | ✅ 已完成 | | 界面美化 | 3 | ✅ 已完成 | | 数据管理功能 | 1 | ✅ 已完成 | +| 主题色支持 | 1 | ✅ 已完成 | | 性能优化 | 4 | 🔄 进行中 | | 新功能开发 | 5 | 📋 计划中 | diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index 2980411374c014260d5733a81be572bbfa52ec4d..c05821f96aac9019f37c8619d8985684a9a93f1f 100644 GIT binary patch delta 9272 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

^R$D*iI%7P>ET%_yj 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 delta 14412 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 z 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 Ef^>DWy8r+H literal 52122 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

~>9JPSXGu6ngRA;DM(Ze<+Lo~oL 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 r3U-|m+^o+38W createState() => _SuggestionsCardState(); +} + +class _SuggestionsCardState extends State { + final ThemeController _themeController = Get.find(); + bool _showAlternativeContent = false; + + @override + Widget build(BuildContext context) { + final isDark = _themeController.isDarkMode; + + return Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: isDark ? const Color(0xFF2A2A2A) : Colors.white, + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: isDark ? 0.3 : 0.05), + blurRadius: 10, + offset: const Offset(0, 2), + ), + ], + ), + child: Column( + children: [ + GestureDetector( + onTap: () { + setState(() { + _showAlternativeContent = !_showAlternativeContent; + }); + }, + child: Row( + children: [ + Icon( + Icons.settings_suggest, + size: 40, + color: AppConstants.primaryColor, + ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '设置建议', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: isDark ? Colors.white : Colors.black, + ), + ), + const SizedBox(height: 4), + Text( + _showAlternativeContent ? '是否在找,清理数据' : '是否在找,主题风格', + style: TextStyle( + fontSize: 13, + color: isDark ? Colors.grey[400] : Colors.grey[600], + ), + ), + ], + ), + ), + Icon(Icons.refresh, color: AppConstants.primaryColor), + ], + ), + ), + const SizedBox(height: 16), + _showAlternativeContent + ? Row( + children: [ + Expanded( + child: _buildActionButton( + '清理数据', + '管理应用数据', + Icons.delete_sweep, + Colors.red, + () => Get.toNamed('/app-data-guide'), + ), + ), + const SizedBox(width: 12), + Expanded( + child: _buildActionButton( + '了解软件', + '查看应用信息', + Icons.info, + Colors.purple, + () => Get.to(() => const AppInfoPage()), + ), + ), + ], + ) + : Row( + children: [ + Expanded( + child: _buildActionButton( + '主题风格', + '自定义应用主题', + Icons.palette, + Colors.blue, + () => Get.to(() => const AppDiyPage()), + ), + ), + const SizedBox(width: 12), + Expanded( + child: _buildActionButton( + '创建笔记', + '快速创建新笔记', + Icons.note_add, + Colors.green, + () => Get.to(() => const CollectNotesPage()), + ), + ), + ], + ), + ], + ), + ); + } + + Widget _buildActionButton( + String title, + String subtitle, + IconData icon, + Color color, + VoidCallback onTap, + ) { + final isDark = _themeController.isDarkMode; + + return InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(8), + child: Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: color.withValues(alpha: 0.1), + borderRadius: BorderRadius.circular(8), + border: Border.all(color: color.withValues(alpha: 0.2), width: 1), + ), + child: Column( + children: [ + Icon(icon, color: color, size: 24), + const SizedBox(height: 4), + Text( + title, + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.bold, + color: isDark ? Colors.white : Colors.black, + ), + ), + const SizedBox(height: 2), + Text( + subtitle, + style: TextStyle( + fontSize: 11, + color: isDark ? Colors.grey[400] : Colors.grey[600], + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index e27c412..fe09b3e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,12 +1,15 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'utils/app_theme.dart'; import 'utils/app_initializer.dart'; import 'utils/force_guide_checker.dart'; import 'routes/app_routes.dart'; import 'constants/app_constants.dart'; +import 'config/app_config.dart'; import 'controllers/shared_preferences_storage_controller.dart'; import 'services/get/theme_controller.dart'; +import 'views/profile/guide/sp-guide.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -16,21 +19,31 @@ void main() async { // 初始化 ThemeController(在 AppInitializer 之前,确保主题最先加载) Get.put(ThemeController(), permanent: true); - final result = await AppInitializer.initialize(); + // 检查是否需要显示引导页 + String initialRoute = await _getInitialRoute(); - runApp( - MyApp( - initialRoute: result.initialRoute, - guideCheckResult: result.guideCheckResult, - ), - ); + runApp(MyApp(initialRoute: initialRoute)); +} + +Future _getInitialRoute() async { + final prefs = await SharedPreferences.getInstance(); + bool agreementAccepted = + prefs.getBool(AppConfig.keyAgreementAccepted) ?? false; + + // 如果协议未被接受,显示引导页 + if (!agreementAccepted) { + return '/sp-guide'; + } + + // 否则使用 AppInitializer 返回的初始路由 + final result = await AppInitializer.initialize(); + return result.initialRoute; } class MyApp extends StatelessWidget { final String initialRoute; - final GuideCheckResult? guideCheckResult; - const MyApp({super.key, required this.initialRoute, this.guideCheckResult}); + const MyApp({super.key, required this.initialRoute}); @override Widget build(BuildContext context) { @@ -45,6 +58,7 @@ class MyApp extends StatelessWidget { themeMode: themeController.currentThemeMode, initialRoute: initialRoute, onGenerateRoute: AppRoutes.generateRoute, + routes: {'/sp-guide': (context) => const SpGuidePage()}, ); }); } diff --git a/lib/models/colors/app_colors.dart b/lib/models/colors/app_colors.dart new file mode 100644 index 0000000..65b4588 --- /dev/null +++ b/lib/models/colors/app_colors.dart @@ -0,0 +1,87 @@ +/// 时间: 2026-04-02 +/// 功能: 应用动态颜色管理 +/// 介绍: 提供基于 ThemeController 的动态颜色获取,支持主题色实时切换 + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import '../../services/get/theme_controller.dart'; + +/// 应用颜色管理类 +/// 使用 GetX 获取当前主题色,支持动态切换 +class AppColors { + /// 获取 ThemeController 实例 + static ThemeController get _themeController => Get.find(); + + /// 当前主题色(动态获取) + static Color get primary => _themeController.currentThemeColor; + + /// 当前强调色(动态获取) + static Color get accent => _themeController.currentAccentColor; + + /// 是否为深色模式 + static bool get isDarkMode => _themeController.isDarkMode; + + /// iOS 系统风格颜色 + static const Color iosBlue = Color(0xFF007AFF); + static const Color iosGreen = Color(0xFF34C759); + static const Color iosRed = Color(0xFFFF3B30); + static const Color iosOrange = Color(0xFFFF9500); + static const Color iosYellow = Color(0xFFFFCC00); + static const Color iosPurple = Color(0xFF5856D6); + static const Color iosTeal = Color(0xFF5AC8FA); + static const Color iosPink = Color(0xFFFF2D55); + static const Color iosIndigo = Color(0xFF5856D6); + static const Color iosGray = Color(0xFF8E8E93); + static const Color iosLightGray = Color(0xFFE5E5EA); + static const Color iosDarkGray = Color(0xFF3C3C43); + + /// 深色模式背景色 + static const Color darkBackground = Color(0xFF1A1A1A); + static const Color darkSurface = Color(0xFF2A2A2A); + static const Color darkCard = Color(0xFF333333); + + /// 浅色模式背景色 + static const Color lightBackground = Color(0xFFF2F2F7); + static const Color lightSurface = Colors.white; + static const Color lightCard = Color(0xFFF2F2F7); + + /// 获取背景色(根据主题模式) + static Color get background => isDarkMode ? darkBackground : lightBackground; + + /// 获取表面色(根据主题模式) + static Color get surface => isDarkMode ? darkSurface : lightSurface; + + /// 获取卡片色(根据主题模式) + static Color get card => isDarkMode ? darkCard : lightCard; + + /// 获取主文本色(根据主题模式) + static Color get primaryText => isDarkMode ? Colors.white : Colors.black; + + /// 获取次文本色(根据主题模式) + static Color get secondaryText => + isDarkMode ? Colors.grey[400]! : iosDarkGray.withAlpha(153); + + /// 获取三级文本色(根据主题模式) + static Color get tertiaryText => isDarkMode ? Colors.grey[500]! : iosGray; + + /// 获取分隔线颜色(根据主题模式) + static Color get divider => isDarkMode ? Colors.grey[700]! : iosLightGray; + + /// 获取带透明度的主题色 + static Color primaryWithAlpha(int alpha) => primary.withAlpha(alpha); + + /// 获取带透明度的强调色 + static Color accentWithAlpha(int alpha) => accent.withAlpha(alpha); + + /// 成功色(绿色,iOS风格) + static const Color success = iosGreen; + + /// 警告色(橙色,iOS风格) + static const Color warning = iosOrange; + + /// 错误色(红色,iOS风格) + static const Color error = iosRed; + + /// 信息色(蓝色,iOS风格) + static const Color info = iosBlue; +} diff --git a/lib/models/colors/theme_colors.dart b/lib/models/colors/theme_colors.dart new file mode 100644 index 0000000..2496fba --- /dev/null +++ b/lib/models/colors/theme_colors.dart @@ -0,0 +1,51 @@ +/// 时间: 2026-04-02 +/// 功能: 主题颜色管理 +/// 介绍: 提供主题颜色的管理和获取功能 + +import 'package:flutter/material.dart'; +import '../../constants/app_constants.dart'; + +class ThemeColors { + // 主题颜色选项 + static const List themeColors = [ + AppConstants.primaryColor, // 默认紫色 + Colors.blue, // 蓝色 + Colors.green, // 绿色 + Colors.orange, // 橙色 + Colors.red, // 红色 + Colors.teal, // 青色 + Color(0xFF8B4513), // 书褐色 - 传统中国风 + ]; + + // 强调色选项 + static const List accentColors = [ + AppConstants.primaryColor, // 默认紫色 + Colors.yellow, // 黄色 + Colors.pink, // 粉色 + Colors.cyan, // 青色 + Colors.purple, // 深紫色 + Color(0xFFF5F5F0), // 宣纸色 - 米白色 + ]; + + // 中国传统色彩 + static const Color ricePaperColor = Color(0xFFF5F5F0); // 宣纸色 - 米白 + static const Color inkBlackColor = Color(0xFF3C2A21); // 墨黑色 + static const Color bookBrownColor = Color(0xFF5D4037); // 书褐色 + static const Color traditionalBrownColor = Color(0xFF8B4513); // 传统褐色 + + // 根据索引获取主题颜色 + static Color getThemeColor(int index) { + if (index >= 0 && index < themeColors.length) { + return themeColors[index]; + } + return themeColors[0]; // 默认返回第一个颜色 + } + + // 根据索引获取强调色 + static Color getAccentColor(int index) { + if (index >= 0 && index < accentColors.length) { + return accentColors[index]; + } + return accentColors[0]; // 默认返回第一个颜色 + } +} diff --git a/lib/views/profile/level/api.md b/lib/services/document/api.md similarity index 100% rename from lib/views/profile/level/api.md rename to lib/services/document/api.md diff --git a/lib/services/get/care_controller.dart b/lib/services/get/care_controller.dart new file mode 100644 index 0000000..d689325 --- /dev/null +++ b/lib/services/get/care_controller.dart @@ -0,0 +1,87 @@ +import 'package:get/get.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class CareController extends GetxController { + static const String _careModeKey = 'care_mode_enabled'; + static const String _userTypeKey = 'care_user_type'; + static const String _pinyinEnabledKey = 'care_pinyin_enabled'; + static const String _selectedOptionsKey = 'care_selected_options'; + static const String _careNavigationIndexKey = 'care_navigation_index'; + + final RxBool _isCareModeEnabled = false.obs; + final RxString _userType = '儿童'.obs; + final RxBool _pinyinEnabled = false.obs; + final RxSet _selectedOptions = {'诗词', '出处'}.obs; + final RxBool isCareButtonVisible = false.obs; + final RxInt _careNavigationIndex = 0.obs; + + bool get isCareModeEnabled => _isCareModeEnabled.value; + String get userType => _userType.value; + bool get pinyinEnabled => _pinyinEnabled.value; + Set get selectedOptions => _selectedOptions.toSet(); + int get careNavigationIndex => _careNavigationIndex.value; + + @override + void onInit() { + super.onInit(); + _loadCareSettings(); + } + + Future _loadCareSettings() async { + final prefs = await SharedPreferences.getInstance(); + _isCareModeEnabled.value = prefs.getBool(_careModeKey) ?? false; + _userType.value = prefs.getString(_userTypeKey) ?? '儿童'; + _pinyinEnabled.value = prefs.getBool(_pinyinEnabledKey) ?? false; + _careNavigationIndex.value = prefs.getInt(_careNavigationIndexKey) ?? 0; + + final savedOptions = prefs.getStringList(_selectedOptionsKey); + if (savedOptions != null && savedOptions.isNotEmpty) { + _selectedOptions.clear(); + _selectedOptions.addAll(savedOptions); + if (!_selectedOptions.contains('诗词')) { + _selectedOptions.add('诗词'); + } + } + } + + Future toggleCareMode() async { + _isCareModeEnabled.value = !_isCareModeEnabled.value; + final prefs = await SharedPreferences.getInstance(); + await prefs.setBool(_careModeKey, _isCareModeEnabled.value); + } + + Future setUserType(String type) async { + _userType.value = type; + final prefs = await SharedPreferences.getInstance(); + await prefs.setString(_userTypeKey, type); + } + + Future setPinyinEnabled(bool enabled) async { + _pinyinEnabled.value = enabled; + final prefs = await SharedPreferences.getInstance(); + await prefs.setBool(_pinyinEnabledKey, enabled); + } + + Future toggleOption(String option) async { + if (option == '诗词') return; // 诗词选项不可取消 + + if (_selectedOptions.contains(option)) { + _selectedOptions.remove(option); + } else { + _selectedOptions.add(option); + } + + final prefs = await SharedPreferences.getInstance(); + await prefs.setStringList(_selectedOptionsKey, _selectedOptions.toList()); + } + + void toggleCareButtonVisibility() { + isCareButtonVisible.value = !isCareButtonVisible.value; + } + + Future switchCareNavigation(int index) async { + _careNavigationIndex.value = index; + final prefs = await SharedPreferences.getInstance(); + await prefs.setInt(_careNavigationIndexKey, index); + } +} diff --git a/lib/services/get/favorites_controller.dart b/lib/services/get/favorites_controller.dart index 502788e..840019f 100644 --- a/lib/services/get/favorites_controller.dart +++ b/lib/services/get/favorites_controller.dart @@ -28,9 +28,13 @@ class FavoritesController extends GetxController { } void showFilterOptions(BuildContext context) { + // 先获取当前值,避免在弹窗中使用 Obx + final currentSortByTime = sortByTime.value; + final currentLikesFirst = likesFirst.value; + showModalBottomSheet( context: context, - builder: (context) => Container( + builder: (BuildContext context) => Container( padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, @@ -43,54 +47,51 @@ class FavoritesController extends GetxController { ListTile( leading: const Icon(Icons.date_range), title: const Text('按时间排序'), - trailing: Obx( - () => Icon( - sortByTime.value - ? Icons.radio_button_checked - : Icons.radio_button_unchecked, - color: AppConstants.primaryColor, - ), + trailing: Icon( + currentSortByTime + ? Icons.radio_button_checked + : Icons.radio_button_unchecked, + color: AppConstants.primaryColor, ), onTap: () { Navigator.pop(context); sortByTime.value = true; - Get.snackbar('提示', '已按时间排序'); - // 触发排序更新 - update(); + // 使用 Future.delayed 确保弹窗完全关闭后再显示 snackbar + Future.delayed(const Duration(milliseconds: 100), () { + Get.snackbar('提示', '已按时间排序'); + }); }, ), ListTile( leading: const Icon(Icons.title), title: const Text('按分类排序'), - trailing: Obx( - () => Icon( - !sortByTime.value - ? Icons.radio_button_checked - : Icons.radio_button_unchecked, - color: AppConstants.primaryColor, - ), + trailing: Icon( + !currentSortByTime + ? Icons.radio_button_checked + : Icons.radio_button_unchecked, + color: AppConstants.primaryColor, ), onTap: () { Navigator.pop(context); sortByTime.value = false; - Get.snackbar('提示', '已按分类排序'); - // 触发排序更新 - update(); + // 使用 Future.delayed 确保弹窗完全关闭后再显示 snackbar + Future.delayed(const Duration(milliseconds: 100), () { + Get.snackbar('提示', '已按分类排序'); + }); }, ), const Divider(), ListTile( leading: const Icon(Icons.swap_vert), - title: Text(likesFirst.value ? '点赞在前' : '笔记在前'), - trailing: Obx( - () => Icon(Icons.swap_vert, color: AppConstants.primaryColor), - ), + title: Text(currentLikesFirst ? '点赞在前' : '笔记在前'), + trailing: Icon(Icons.swap_vert, color: AppConstants.primaryColor), onTap: () { Navigator.pop(context); likesFirst.value = !likesFirst.value; - Get.snackbar('提示', likesFirst.value ? '点赞在前' : '笔记在前'); - // 触发顺序更新 - update(); + // 使用 Future.delayed 确保弹窗完全关闭后再显示 snackbar + Future.delayed(const Duration(milliseconds: 100), () { + Get.snackbar('提示', likesFirst.value ? '点赞在前' : '笔记在前'); + }); }, ), ], diff --git a/lib/services/get/theme_controller.dart b/lib/services/get/theme_controller.dart index 5d1e057..f54b3e3 100644 --- a/lib/services/get/theme_controller.dart +++ b/lib/services/get/theme_controller.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import '../../models/colors/theme_colors.dart'; import '../../models/night-mode/theme_model.dart'; /// 主题控制器 @@ -40,6 +41,14 @@ class ThemeController extends GetxController { bool get enableAnimation => _enableAnimation.value; bool get enableBlurEffect => _enableBlurEffect.value; + // 获取当前主题颜色 + Color get currentThemeColor => + ThemeColors.getThemeColor(_themeColorIndex.value); + + // 获取当前强调色 + Color get currentAccentColor => + ThemeColors.getAccentColor(_accentColorIndex.value); + /// 获取当前 Flutter ThemeMode ThemeMode get currentThemeMode { if (_isDarkMode.value) { @@ -71,9 +80,11 @@ class ThemeController extends GetxController { _prefs = await SharedPreferences.getInstance(); _isDarkMode.value = _prefs?.getBool(_darkModeKey) ?? false; - _themeMode.value = AppThemeMode.values[ - (_prefs?.getInt(_themeModeKey) ?? 0).clamp(0, AppThemeMode.values.length - 1) - ]; + _themeMode.value = + AppThemeMode.values[(_prefs?.getInt(_themeModeKey) ?? 0).clamp( + 0, + AppThemeMode.values.length - 1, + )]; _themeColorIndex.value = _prefs?.getInt(_themeColorIndexKey) ?? 0; _accentColorIndex.value = _prefs?.getInt(_accentColorIndexKey) ?? 0; _fontSizeIndex.value = _prefs?.getInt(_fontSizeIndexKey) ?? 1; @@ -102,6 +113,14 @@ class ThemeController extends GetxController { Get.changeThemeMode(currentThemeMode); } + /// 应用主题颜色到 GetX + void _applyThemeColor() { + // 这里可以根据需要创建新的主题并应用 + // 由于我们使用的是 GetX 的主题系统, + // 我们可以通过更新全局状态来让组件响应主题颜色变化 + update(); + } + /// 切换深色模式 /// [enabled] true 开启深色模式, false 关闭深色模式 Future toggleDarkMode(bool enabled) async { @@ -144,6 +163,17 @@ class ThemeController extends GetxController { _themeColorIndex.value = index; await _saveThemeSettings(); + _applyThemeColor(); + + // 显示提示 + Get.snackbar( + '主题颜色', + '已更换主题颜色', + snackPosition: SnackPosition.BOTTOM, + duration: const Duration(seconds: 2), + margin: const EdgeInsets.all(16), + borderRadius: 12, + ); } /// 设置强调色索引 @@ -152,6 +182,17 @@ class ThemeController extends GetxController { _accentColorIndex.value = index; await _saveThemeSettings(); + _applyThemeColor(); + + // 显示提示 + Get.snackbar( + '强调颜色', + '已更换强调颜色', + snackPosition: SnackPosition.BOTTOM, + duration: const Duration(seconds: 2), + margin: const EdgeInsets.all(16), + borderRadius: 12, + ); } /// 设置字体大小索引 diff --git a/lib/views/active/active_search_page.dart b/lib/views/active/active_search_page.dart index e24efb8..5370052 100644 --- a/lib/views/active/active_search_page.dart +++ b/lib/views/active/active_search_page.dart @@ -304,7 +304,8 @@ class _ActiveSearchPageState extends State ), ), selected: _field.isEmpty, - selectedColor: AppConstants.primaryColor, + selectedColor: + _themeController.currentThemeColor, backgroundColor: isDark ? Colors.grey[800] : Colors.grey[200], @@ -327,7 +328,8 @@ class _ActiveSearchPageState extends State ), ), selected: _field == 'name', - selectedColor: AppConstants.primaryColor, + selectedColor: + _themeController.currentThemeColor, backgroundColor: isDark ? Colors.grey[800] : Colors.grey[200], @@ -350,7 +352,8 @@ class _ActiveSearchPageState extends State ), ), selected: _field == 'keywords', - selectedColor: AppConstants.primaryColor, + selectedColor: + _themeController.currentThemeColor, backgroundColor: isDark ? Colors.grey[800] : Colors.grey[200], @@ -373,7 +376,8 @@ class _ActiveSearchPageState extends State ), ), selected: _field == 'introduce', - selectedColor: AppConstants.primaryColor, + selectedColor: + _themeController.currentThemeColor, backgroundColor: isDark ? Colors.grey[800] : Colors.grey[200], @@ -402,7 +406,7 @@ class _ActiveSearchPageState extends State ), Expanded( child: RefreshIndicator( - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, onRefresh: () async { await _runSearch(reset: true); }, @@ -426,7 +430,7 @@ class _ActiveSearchPageState extends State ); } }, - backgroundColor: AppConstants.primaryColor, + backgroundColor: _themeController.currentThemeColor, foregroundColor: Colors.white, tooltip: '返回上一页', child: const Icon(Icons.arrow_back), diff --git a/lib/views/active/category_page.dart b/lib/views/active/category_page.dart index 4c820eb..23ac10a 100644 --- a/lib/views/active/category_page.dart +++ b/lib/views/active/category_page.dart @@ -19,6 +19,7 @@ class CategoryPage extends StatelessWidget { return Obx(() { final isDark = themeController.isDarkModeRx.value; + final themeColor = themeController.currentThemeColor; return Column( children: [ @@ -41,11 +42,11 @@ class CategoryPage extends StatelessWidget { ), ) .toList(), - labelColor: AppConstants.primaryColor, + labelColor: themeColor, unselectedLabelColor: isDark ? Colors.grey[400] : Colors.grey[600], - indicatorColor: AppConstants.primaryColor, + indicatorColor: themeColor, indicatorWeight: 3, labelStyle: const TextStyle( fontWeight: FontWeight.w600, @@ -71,11 +72,13 @@ class CategoryPage extends StatelessWidget { controller.sceneData, controller.tabCategories[0]['label'] as String, isDark, + themeColor, ), _buildCategoryList( controller.dynastyData, controller.tabCategories[1]['label'] as String, isDark, + themeColor, ), ], ), @@ -90,6 +93,7 @@ class CategoryPage extends StatelessWidget { Map> data, String categoryType, bool isDark, + Color themeColor, ) { return ListView.separated( padding: const EdgeInsets.symmetric(vertical: 8), @@ -138,14 +142,14 @@ class CategoryPage extends StatelessWidget { vertical: 4, ), decoration: BoxDecoration( - color: AppConstants.primaryColor.withAlpha(26), + color: themeColor.withAlpha(26), borderRadius: BorderRadius.circular(12), ), child: Text( '${items.length}', style: TextStyle( fontSize: 13, - color: AppConstants.primaryColor, + color: themeColor, fontWeight: FontWeight.w600, ), ), @@ -157,7 +161,12 @@ class CategoryPage extends StatelessWidget { spacing: 10, runSpacing: 10, children: items.map((item) { - return _buildCategoryChip(item, categoryType, isDark); + return _buildCategoryChip( + item, + categoryType, + isDark, + themeColor, + ); }).toList(), ), ], @@ -169,7 +178,12 @@ class CategoryPage extends StatelessWidget { ); } - Widget _buildCategoryChip(String label, String categoryType, bool isDark) { + Widget _buildCategoryChip( + String label, + String categoryType, + bool isDark, + Color themeColor, + ) { final controller = Get.find(); return GestureDetector( @@ -179,17 +193,14 @@ class CategoryPage extends StatelessWidget { child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), decoration: BoxDecoration( - color: AppConstants.primaryColor.withAlpha(26), + color: themeColor.withAlpha(26), borderRadius: BorderRadius.circular(20), - border: Border.all( - color: AppConstants.primaryColor.withAlpha(77), - width: 1, - ), + border: Border.all(color: themeColor.withAlpha(77), width: 1), ), child: Text( label, style: TextStyle( - color: AppConstants.primaryColor, + color: themeColor, fontSize: 14, fontWeight: FontWeight.w500, ), diff --git a/lib/views/active/popular_page.dart b/lib/views/active/popular_page.dart index 2ee3098..f5bc5af 100644 --- a/lib/views/active/popular_page.dart +++ b/lib/views/active/popular_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import '../../constants/app_constants.dart'; import '../../config/app_config.dart'; import '../../utils/http/http_client.dart'; @@ -6,6 +7,7 @@ import '../../models/poetry_model.dart'; import '../../controllers/load/locally.dart'; import '../../controllers/history_controller.dart'; import '../../services/network_listener_service.dart'; +import '../../services/get/theme_controller.dart'; /// 时间: 2026-03-25 /// 功能: 热门页面 @@ -22,6 +24,7 @@ class PopularPage extends StatefulWidget { class _PopularPageState extends State with SingleTickerProviderStateMixin { late TabController _tabController; + final ThemeController _themeController = Get.find(); final List> _tabCategories = [ {'label': '总榜', 'icon': Icons.bar_chart}, {'label': '日榜', 'icon': Icons.today}, @@ -53,58 +56,81 @@ class _PopularPageState extends State @override Widget build(BuildContext context) { - return Column( - children: [ - // 黑色分割线 - Container(height: 1, color: Colors.black.withValues(alpha: 0.1)), - // Tab栏 - Container( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), - child: TabBar( - controller: _tabController, - tabs: _tabCategories - .map( - (category) => Tab( - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(category['icon'], size: 16), - const SizedBox(width: 6), - Text(category['label']), - ], + return Obx(() { + final isDark = _themeController.isDarkModeRx.value; + final themeColor = _themeController.currentThemeColor; + + return Column( + children: [ + // 分割线 + Container( + height: 1, + color: isDark ? Colors.grey[800] : Colors.black.withAlpha(10), + ), + // Tab栏 + Container( + color: isDark ? Colors.grey[900] : Colors.white, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + child: TabBar( + controller: _tabController, + tabs: _tabCategories + .map( + (category) => Tab( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(category['icon'], size: 16), + const SizedBox(width: 6), + Text(category['label']), + ], + ), ), - ), - ) - .toList(), - labelColor: AppConstants.primaryColor, - unselectedLabelColor: Colors.grey[600], - indicatorColor: AppConstants.primaryColor, - indicatorWeight: 3, - labelStyle: const TextStyle(fontWeight: FontWeight.bold), + ) + .toList(), + labelColor: themeColor, + unselectedLabelColor: isDark + ? Colors.grey[400] + : Colors.grey[600], + indicatorColor: themeColor, + indicatorWeight: 3, + labelStyle: const TextStyle(fontWeight: FontWeight.bold), + ), ), - ), - // 内容区域 - Expanded( - child: TabBarView( - controller: _tabController, - children: _tabCategories.map((category) { - return _buildRankContent(category['label']); - }).toList(), + // 内容区域 + Expanded( + child: Container( + color: isDark ? const Color(0xFF121212) : Colors.grey[50], + child: TabBarView( + controller: _tabController, + children: _tabCategories.map((category) { + return _buildRankContent( + category['label'], + isDark, + themeColor, + ); + }).toList(), + ), + ), ), - ), - ], - ); + ], + ); + }); } - Widget _buildRankContent(String category) { + Widget _buildRankContent(String category, bool isDark, Color themeColor) { if (_loading) { - return const Center( + return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - CircularProgressIndicator(), - SizedBox(height: 16), - Text('正在加载排行榜...'), + CircularProgressIndicator(color: themeColor), + const SizedBox(height: 16), + Text( + '正在加载排行榜...', + style: TextStyle( + color: isDark ? Colors.grey[300] : Colors.grey[600], + ), + ), ], ), ); @@ -115,12 +141,25 @@ class _PopularPageState extends State child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - const Icon(Icons.error_outline, size: 64, color: Colors.grey), + Icon( + Icons.error_outline, + size: 64, + color: isDark ? Colors.grey[500] : Colors.grey[400], + ), const SizedBox(height: 16), - Text(_errorMessage, style: const TextStyle(color: Colors.grey)), + Text( + _errorMessage, + style: TextStyle( + color: isDark ? Colors.grey[400] : Colors.grey[600], + ), + ), const SizedBox(height: 16), ElevatedButton( onPressed: _loadRankList, + style: ElevatedButton.styleFrom( + backgroundColor: themeColor, + foregroundColor: Colors.white, + ), child: const Text('🔄 重试'), ), ], @@ -129,17 +168,29 @@ class _PopularPageState extends State } if (_rankList.isEmpty) { - return const Center( + return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.bar_chart, size: 64, color: Colors.grey), - SizedBox(height: 16), - Text('暂无排行数据', style: TextStyle(color: Colors.grey)), - SizedBox(height: 8), + Icon( + Icons.bar_chart, + size: 64, + color: isDark ? Colors.grey[500] : Colors.grey[400], + ), + const SizedBox(height: 16), + Text( + '暂无排行数据', + style: TextStyle( + color: isDark ? Colors.grey[400] : Colors.grey[600], + ), + ), + const SizedBox(height: 8), Text( '换个时间段试试吧', - style: TextStyle(color: Colors.grey, fontSize: 12), + style: TextStyle( + color: isDark ? Colors.grey[500] : Colors.grey[600], + fontSize: 12, + ), ), ], ), @@ -147,6 +198,7 @@ class _PopularPageState extends State } return RefreshIndicator( + color: themeColor, onRefresh: () async => await _loadRankList(forceRefresh: true), child: NotificationListener( onNotification: (scrollNotification) { @@ -167,14 +219,24 @@ class _PopularPageState extends State itemCount: _rankList.length + (_showBottomIndicator ? 1 : 0), itemBuilder: (context, index) { if (index == _rankList.length) { - return const Center( + return Center( child: Padding( - padding: EdgeInsets.all(16), - child: Text('到底了', style: TextStyle(color: Colors.grey)), + padding: const EdgeInsets.all(16), + child: Text( + '到底了', + style: TextStyle( + color: isDark ? Colors.grey[500] : Colors.grey[600], + ), + ), ), ); } - return _buildRankItem(_rankList[index], index + 1); + return _buildRankItem( + _rankList[index], + index + 1, + isDark, + themeColor, + ); }, ), ), @@ -223,19 +285,23 @@ class _PopularPageState extends State } } - Widget _buildRankItem(PoetryModel poetry, int index) { + Widget _buildRankItem( + PoetryModel poetry, + int index, + bool isDark, + Color themeColor, + ) { final rank = poetry.rank > 0 ? poetry.rank : index; final isTopThree = rank <= 3; return Card( margin: const EdgeInsets.only(bottom: 12), elevation: isTopThree ? 4 : 2, + color: isDark ? Colors.grey[850] : Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), side: BorderSide( - color: isTopThree - ? AppConstants.primaryColor - : AppConstants.primaryColor.withValues(alpha: 0.2), + color: isTopThree ? themeColor : themeColor.withAlpha(20), width: isTopThree ? 2 : 1, ), ), @@ -254,16 +320,12 @@ class _PopularPageState extends State width: 40, height: 40, decoration: BoxDecoration( - color: isTopThree - ? AppConstants.primaryColor - : AppConstants.primaryColor.withValues(alpha: 0.3), + color: isTopThree ? themeColor : themeColor.withAlpha(30), borderRadius: BorderRadius.circular(20), border: isTopThree ? null : Border.all( - color: AppConstants.primaryColor.withValues( - alpha: 0.2, - ), + color: themeColor.withAlpha(20), width: 1, ), ), @@ -273,9 +335,7 @@ class _PopularPageState extends State style: TextStyle( color: isTopThree ? Colors.white - : AppConstants.primaryColor.withValues( - alpha: 0.8, - ), + : themeColor.withAlpha(80), fontWeight: FontWeight.bold, fontSize: 16, ), @@ -292,8 +352,11 @@ class _PopularPageState extends State // 标题 Text( poetry.name, - style: Theme.of(context).textTheme.titleMedium - ?.copyWith(fontWeight: FontWeight.bold), + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + color: isDark ? Colors.white : Colors.black87, + ), maxLines: 2, overflow: TextOverflow.ellipsis, ), @@ -310,16 +373,14 @@ class _PopularPageState extends State vertical: 2, ), decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues( - alpha: 0.1, - ), + color: themeColor.withAlpha(10), borderRadius: BorderRadius.circular(8), ), child: Text( poetry.alias, style: TextStyle( fontSize: 10, - color: AppConstants.primaryColor, + color: themeColor, ), ), ), @@ -331,7 +392,9 @@ class _PopularPageState extends State poetry.url, style: TextStyle( fontSize: 12, - color: Colors.grey[600], + color: isDark + ? Colors.grey[400] + : Colors.grey[600], ), overflow: TextOverflow.ellipsis, ), @@ -347,21 +410,29 @@ class _PopularPageState extends State '👁', poetry.hitsTotal.toString(), '总浏览', + isDark, ), const SizedBox(width: 16), - _buildStatItem('💖', poetry.like.toString(), '点赞'), + _buildStatItem( + '💖', + poetry.like.toString(), + '点赞', + isDark, + ), const SizedBox(width: 16), if (_tabController.index == 1) _buildStatItem( '📅', poetry.hitsDay.toString(), '今日', + isDark, ), if (_tabController.index == 2) _buildStatItem( '📊', poetry.hitsMonth.toString(), '本月', + isDark, ), ], ), @@ -382,14 +453,14 @@ class _PopularPageState extends State vertical: 6, ), decoration: BoxDecoration( - color: Colors.orange[700], + color: themeColor, borderRadius: const BorderRadius.only( topLeft: Radius.circular(12), bottomRight: Radius.circular(12), ), boxShadow: [ BoxShadow( - color: Colors.black.withValues(alpha: 0.15), + color: Colors.black.withAlpha(15), blurRadius: 4, offset: const Offset(0, 2), ), @@ -424,7 +495,7 @@ class _PopularPageState extends State ); } - Widget _buildStatItem(String icon, String value, String label) { + Widget _buildStatItem(String icon, String value, String label, bool isDark) { return Row( mainAxisSize: MainAxisSize.min, children: [ @@ -432,10 +503,20 @@ class _PopularPageState extends State const SizedBox(width: 4), Text( value, - style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500), + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: isDark ? Colors.grey[300] : Colors.black87, + ), ), const SizedBox(width: 2), - Text(label, style: TextStyle(fontSize: 10, color: Colors.grey[600])), + Text( + label, + style: TextStyle( + fontSize: 10, + color: isDark ? Colors.grey[500] : Colors.grey[600], + ), + ), ], ); } diff --git a/lib/views/active/rate.dart b/lib/views/active/rate.dart index 82f69ec..8b6d043 100644 --- a/lib/views/active/rate.dart +++ b/lib/views/active/rate.dart @@ -70,9 +70,9 @@ class _RatePageState extends State child: TabBar( controller: _tabController, tabs: _tabs.map((tab) => Tab(text: tab)).toList(), - labelColor: AppConstants.primaryColor, - unselectedLabelColor: isDark ? Colors.grey[400] : Colors.grey[600], - indicatorColor: AppConstants.primaryColor, + labelColor: _themeController.currentThemeColor, + unselectedLabelColor: isDark ? Colors.grey[400] : Colors.grey[600], + indicatorColor: _themeController.currentThemeColor, indicatorWeight: 2, labelStyle: const TextStyle(fontWeight: FontWeight.w600), ), @@ -438,27 +438,29 @@ class _RatePageState extends State } Color _getActivityColor(int value) { + final themeColor = _themeController.currentThemeColor; if (value == 0) { return Colors.grey[100]!; } else if (value >= 1 && value <= 5) { - return AppConstants.primaryColor.withAlpha(77); + return themeColor.withAlpha(77); } else if (value >= 6 && value <= 20) { - return AppConstants.primaryColor.withAlpha(128); + return themeColor.withAlpha(128); } else if (value >= 21 && value <= 100) { - return AppConstants.primaryColor.withAlpha(179); + return themeColor.withAlpha(179); } else { - return AppConstants.primaryColor; + return themeColor; } } Widget _buildSectionTitle(String title, bool isDark) { + final themeColor = _themeController.currentThemeColor; return Row( children: [ Container( width: 4, height: 20, decoration: BoxDecoration( - color: AppConstants.primaryColor, + color: themeColor, borderRadius: BorderRadius.circular(2), ), ), @@ -497,9 +499,10 @@ class _RatePageState extends State } Widget _buildStatItem(String label, String value, IconData icon, bool isDark) { + final themeColor = _themeController.currentThemeColor; return Column( children: [ - Icon(icon, color: AppConstants.primaryColor, size: 24), + Icon(icon, color: themeColor, size: 24), const SizedBox(height: 8), Text( value, @@ -512,6 +515,7 @@ class _RatePageState extends State } Widget _buildLegend(bool isDark) { + final themeColor = _themeController.currentThemeColor; return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( @@ -531,10 +535,10 @@ class _RatePageState extends State runSpacing: 8, children: [ _buildLegendItem('无活跃', Colors.grey[100]!, isDark), - _buildLegendItem('1-5', AppConstants.primaryColor.withAlpha(77), isDark), - _buildLegendItem('6-20', AppConstants.primaryColor.withAlpha(128), isDark), - _buildLegendItem('21-100', AppConstants.primaryColor.withAlpha(179), isDark), - _buildLegendItem('100+', AppConstants.primaryColor, isDark), + _buildLegendItem('1-5', themeColor.withAlpha(77), isDark), + _buildLegendItem('6-20', themeColor.withAlpha(128), isDark), + _buildLegendItem('21-100', themeColor.withAlpha(179), isDark), + _buildLegendItem('100+', themeColor, isDark), ], ), ], diff --git a/lib/views/active/tags/corr_page.dart b/lib/views/active/tags/corr_page.dart index 02fca57..50fcf3b 100644 --- a/lib/views/active/tags/corr_page.dart +++ b/lib/views/active/tags/corr_page.dart @@ -231,7 +231,10 @@ class _CorrPageState extends State backgroundColor: isDark ? Colors.grey[900] : Colors.white, elevation: 0, leading: IconButton( - icon: Icon(Icons.arrow_back_ios, color: AppConstants.primaryColor), + icon: Icon( + Icons.arrow_back_ios, + color: _themeController.currentThemeColor, + ), onPressed: () => Navigator.pop(context), ), title: Column( @@ -298,7 +301,7 @@ class _CorrPageState extends State duration: const Duration(milliseconds: 300), child: RefreshIndicator( key: const ValueKey('list'), - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, onRefresh: _loadData, child: ListView.builder( controller: _scrollController, @@ -428,7 +431,7 @@ class _CorrPageState extends State ElevatedButton( onPressed: _loadData, style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: _themeController.currentThemeColor, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 32, @@ -486,7 +489,7 @@ class _CorrPageState extends State height: 24, child: CircularProgressIndicator( strokeWidth: 2, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, ), ), ), @@ -544,14 +547,16 @@ class _CorrPageState extends State vertical: 4, ), decoration: BoxDecoration( - color: AppConstants.primaryColor.withAlpha(26), + color: _themeController.currentThemeColor.withAlpha( + 26, + ), borderRadius: BorderRadius.circular(8), ), child: Text( alias, style: TextStyle( fontSize: 12, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, fontWeight: FontWeight.w500, ), ), @@ -808,14 +813,18 @@ class _CorrPageState extends State }, icon: Icon( Icons.note_add, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, ), label: Text( '创建笔记', - style: TextStyle(color: AppConstants.primaryColor), + style: TextStyle( + color: _themeController.currentThemeColor, + ), ), style: OutlinedButton.styleFrom( - side: BorderSide(color: AppConstants.primaryColor), + side: BorderSide( + color: _themeController.currentThemeColor, + ), padding: const EdgeInsets.symmetric(vertical: 12), ), ), @@ -827,7 +836,7 @@ class _CorrPageState extends State icon: const Icon(Icons.favorite, color: Colors.white), label: const Text('点赞'), style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: _themeController.currentThemeColor, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 12), ), diff --git a/lib/views/discover_page.dart b/lib/views/discover_page.dart index d67a097..c80e24e 100644 --- a/lib/views/discover_page.dart +++ b/lib/views/discover_page.dart @@ -74,7 +74,7 @@ class _DiscoverPageState extends State backgroundColor: isDark ? Colors.grey[900] : Colors.white, foregroundColor: isDark ? Colors.white - : AppConstants.primaryColor, + : _themeController.currentThemeColor, leading: controller.categories[_tabController.index] == '热门' ? _buildInfoButton(context, isDark) : null, @@ -139,7 +139,7 @@ class _DiscoverPageState extends State child: Text( '💡 探索更多精彩内容,发现你感兴趣的诗词世界', style: TextStyle( - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, fontSize: 14, fontWeight: FontWeight.w400, ), @@ -213,12 +213,12 @@ class _DiscoverPageState extends State children: [ CircleAvatar( radius: 20, - backgroundColor: AppConstants.primaryColor.withValues( + backgroundColor: _themeController.currentThemeColor.withValues( alpha: 0.1, ), child: Icon( Icons.person, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, size: 20, ), ), @@ -365,7 +365,7 @@ class _DiscoverPageState extends State return IconButton( icon: Icon( Icons.info_outline, - color: isDark ? Colors.white : AppConstants.primaryColor, + color: isDark ? Colors.white : _themeController.currentThemeColor, ), onPressed: () => _showHotInfoPopup(buttonContext, isDark), ); @@ -414,7 +414,7 @@ class _DiscoverPageState extends State children: [ Icon( Icons.local_fire_department, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, size: 20, ), const SizedBox(width: 8), diff --git a/lib/views/favorites_page.dart b/lib/views/favorites_page.dart index 12f50f8..d52b1fb 100644 --- a/lib/views/favorites_page.dart +++ b/lib/views/favorites_page.dart @@ -72,8 +72,10 @@ class _FavoritesPageState extends State tabBarScrollable: true, tabLabelPadding: const EdgeInsets.symmetric(horizontal: 10), backgroundColor: isDark ? const Color(0xFF1A1A1A) : Colors.white, - foregroundColor: isDark ? Colors.white : Colors.black87, - actions: _buildAppBarActions(controller), + foregroundColor: isDark + ? Colors.white + : themeController.currentThemeColor, + actions: _buildAppBarActions(controller, context), ), body: Column( children: [ @@ -93,12 +95,20 @@ class _FavoritesPageState extends State } // 构建AppBar操作按钮 - List _buildAppBarActions(FavoritesController controller) { - final currentCategory = - controller.categories[controller.currentTabIndex.value]; + List _buildAppBarActions( + FavoritesController controller, + BuildContext context, + ) { final isDark = themeController.isDarkMode; List actions = [ + // 统一显示添加笔记按钮 + IconButton( + icon: Icon(Icons.add, color: isDark ? Colors.white70 : null), + onPressed: () { + Get.to(const CollectNotesPage()); + }, + ), IconButton( icon: Icon( controller.isGridView.value ? Icons.view_list : Icons.grid_view, @@ -108,23 +118,15 @@ class _FavoritesPageState extends State ), IconButton( icon: Icon(Icons.filter_list, color: isDark ? Colors.white70 : null), - onPressed: () => controller.showFilterOptions(context), + onPressed: () { + // 使用 Get.context 而不是传递的 context + if (Get.context != null) { + controller.showFilterOptions(Get.context!); + } + }, ), ]; - // 只在笔记页面显示添加笔记按钮 - if (currentCategory == '笔记') { - actions.insert( - 0, - IconButton( - icon: Icon(Icons.add, color: isDark ? Colors.white70 : null), - onPressed: () { - Get.to(const CollectNotesPage()); - }, - ), - ); - } - return actions; } diff --git a/lib/views/footprint/all_list.dart b/lib/views/footprint/all_list.dart index 1690f94..3a69fb8 100644 --- a/lib/views/footprint/all_list.dart +++ b/lib/views/footprint/all_list.dart @@ -178,11 +178,12 @@ class AllListPageState extends State { Widget build(BuildContext context) { return Obx(() { final isDark = _themeController.isDarkMode; + final themeColor = _themeController.currentThemeColor; if (_isLoading && _cards.isEmpty) { return Center( child: CircularProgressIndicator( - color: isDark ? Colors.white : AppConstants.primaryColor, + color: isDark ? Colors.white : themeColor, ), ); } @@ -216,7 +217,7 @@ class AllListPageState extends State { if (index == _cards.length) { return _buildBottomIndicator(isDark); } - return _buildCard(_cards[index], isDark); + return _buildCard(_cards[index], isDark, themeColor); }, ), ); @@ -285,25 +286,22 @@ class AllListPageState extends State { ); } - Widget _buildCard(UnifiedCard card, bool isDark) { + Widget _buildCard(UnifiedCard card, bool isDark, Color themeColor) { switch (card.type) { case CardType.like: - return _buildLikeCard(card.data as PoetryData, isDark); + return _buildLikeCard(card.data as PoetryData, isDark, themeColor); case CardType.note: return _buildNoteCard(card.data as Map, isDark); } } - Widget _buildLikeCard(PoetryData poetry, bool isDark) { + Widget _buildLikeCard(PoetryData poetry, bool isDark, Color themeColor) { return Container( margin: const EdgeInsets.only(bottom: 0), decoration: BoxDecoration( color: isDark ? const Color(0xFF2A2A2A) : Colors.white, borderRadius: BorderRadius.circular(10), - border: Border.all( - color: AppConstants.primaryColor.withValues(alpha: 0.2), - width: 1, - ), + border: Border.all(color: themeColor.withValues(alpha: 0.2), width: 1), boxShadow: [ BoxShadow( color: isDark @@ -340,7 +338,7 @@ class AllListPageState extends State { vertical: 4, ), decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: themeColor.withValues(alpha: 0.1), borderRadius: const BorderRadius.only( topRight: Radius.circular(10), bottomLeft: Radius.circular(10), @@ -349,17 +347,13 @@ class AllListPageState extends State { child: Row( mainAxisSize: MainAxisSize.min, children: [ - Icon( - Icons.favorite, - size: 12, - color: AppConstants.primaryColor, - ), + Icon(Icons.favorite, size: 12, color: themeColor), const SizedBox(width: 3), Text( '点赞诗词', style: TextStyle( fontSize: 11, - color: AppConstants.primaryColor, + color: themeColor, fontWeight: FontWeight.w500, ), ), @@ -391,17 +385,10 @@ class AllListPageState extends State { children: [ TextButton.icon( onPressed: () => _showPoetryDetails(poetry), - icon: Icon( - Icons.visibility, - size: 14, - color: AppConstants.primaryColor, - ), + icon: Icon(Icons.visibility, size: 14, color: themeColor), label: Text( '查看详情', - style: TextStyle( - fontSize: 12, - color: AppConstants.primaryColor, - ), + style: TextStyle(fontSize: 12, color: themeColor), ), ), const Spacer(), diff --git a/lib/views/footprint/collect_notes.dart b/lib/views/footprint/collect_notes.dart index 29030bf..f4aaabb 100644 --- a/lib/views/footprint/collect_notes.dart +++ b/lib/views/footprint/collect_notes.dart @@ -198,6 +198,8 @@ class _CollectNotesPageState extends State { // 显示密码设置对话框 Future _showPasswordDialog() async { + final themeColor = _themeController.currentThemeColor; + final isDark = _themeController.isDarkMode; if (_password != null && _password!.isNotEmpty) { final action = await showDialog( context: context, @@ -207,7 +209,7 @@ class _CollectNotesPageState extends State { ), title: Row( children: [ - Icon(Icons.lock, color: AppConstants.primaryColor, size: 24), + Icon(Icons.lock, color: themeColor, size: 24), const SizedBox(width: 8), const Text('锁定设置'), ], @@ -218,18 +220,22 @@ class _CollectNotesPageState extends State { Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( - color: Colors.grey[100], + color: isDark ? Colors.grey[800] : Colors.grey[100], borderRadius: BorderRadius.circular(8), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.vpn_key, size: 16, color: Colors.grey[600]), + Icon( + Icons.vpn_key, + size: 16, + color: isDark ? Colors.grey[400] : Colors.grey[600], + ), const SizedBox(width: 8), Text( '当前密码: $_password', style: TextStyle( - color: Colors.grey[700], + color: isDark ? Colors.grey[400] : Colors.grey[700], fontSize: 13, fontWeight: FontWeight.w500, ), @@ -282,25 +288,21 @@ class _CollectNotesPageState extends State { horizontal: 16, ), decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: themeColor.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(12), border: Border.all( - color: AppConstants.primaryColor.withValues(alpha: 0.3), + color: themeColor.withValues(alpha: 0.3), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( - Icons.edit, - color: AppConstants.primaryColor, - size: 22, - ), + Icon(Icons.edit, color: themeColor, size: 22), const SizedBox(width: 10), Text( '修改密码', style: TextStyle( - color: AppConstants.primaryColor, + color: themeColor, fontSize: 15, fontWeight: FontWeight.w600, ), @@ -555,6 +557,7 @@ class _CollectNotesPageState extends State { Widget build(BuildContext context) { return Obx(() { final isDark = _themeController.isDarkMode; + final themeColor = _themeController.currentThemeColor; return Scaffold( backgroundColor: isDark ? const Color(0xFF1A1A1A) @@ -565,7 +568,7 @@ class _CollectNotesPageState extends State { leading: IconButton( icon: Icon( Icons.arrow_back, - color: isDark ? Colors.white70 : AppConstants.primaryColor, + color: isDark ? Colors.white70 : themeColor, ), onPressed: () => Navigator.of(context).pop(), ), @@ -590,7 +593,7 @@ class _CollectNotesPageState extends State { icon: Icon( _isLocked ? Icons.lock : Icons.lock_outline, color: _isLocked - ? AppConstants.primaryColor + ? themeColor : (isDark ? Colors.grey[400] : Colors.grey[600]), ), onPressed: _showPasswordDialog, @@ -600,7 +603,7 @@ class _CollectNotesPageState extends State { icon: Icon( _isPinned ? Icons.push_pin : Icons.push_pin_outlined, color: _isPinned - ? AppConstants.primaryColor + ? themeColor : (isDark ? Colors.grey[400] : Colors.grey[600]), ), onPressed: _togglePin, @@ -611,7 +614,7 @@ class _CollectNotesPageState extends State { body: _isLoading ? Center( child: CircularProgressIndicator( - color: isDark ? Colors.white : AppConstants.primaryColor, + color: isDark ? Colors.white : themeColor, ), ) : GestureDetector( @@ -621,7 +624,7 @@ class _CollectNotesPageState extends State { }, child: Column( children: [ - _buildStatusBar(isDark), + _buildStatusBar(isDark, themeColor), Expanded( child: SingleChildScrollView( padding: const EdgeInsets.all(16), @@ -629,9 +632,9 @@ class _CollectNotesPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - _buildTitleInput(isDark), + _buildTitleInput(isDark, themeColor), const SizedBox(height: 16), - _buildContentInput(isDark), + _buildContentInput(isDark, themeColor), ], ), ), @@ -643,7 +646,7 @@ class _CollectNotesPageState extends State { }); } - Widget _buildStatusBar(bool isDark) { + Widget _buildStatusBar(bool isDark, Color themeColor) { return Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[50], @@ -696,27 +699,15 @@ class _CollectNotesPageState extends State { ), if (_isPinned) ...[ const SizedBox(width: 16), - Icon(Icons.push_pin, size: 14, color: AppConstants.primaryColor), + Icon(Icons.push_pin, size: 14, color: themeColor), const SizedBox(width: 4), - Text( - '已置顶', - style: TextStyle( - fontSize: 12, - color: AppConstants.primaryColor, - ), - ), + Text('已置顶', style: TextStyle(fontSize: 12, color: themeColor)), ], if (_isLocked) ...[ const SizedBox(width: 16), - Icon(Icons.lock, size: 14, color: AppConstants.primaryColor), + Icon(Icons.lock, size: 14, color: themeColor), const SizedBox(width: 4), - Text( - '已锁定', - style: TextStyle( - fontSize: 12, - color: AppConstants.primaryColor, - ), - ), + Text('已锁定', style: TextStyle(fontSize: 12, color: themeColor)), ], ], ), @@ -776,7 +767,7 @@ class _CollectNotesPageState extends State { ); } - Widget _buildTitleInput(bool isDark) { + Widget _buildTitleInput(bool isDark, Color themeColor) { return Row( children: [ Expanded( @@ -786,7 +777,7 @@ class _CollectNotesPageState extends State { borderRadius: BorderRadius.circular(12), border: Border.all( color: _titleFocusNode.hasFocus - ? AppConstants.primaryColor.withValues(alpha: 0.5) + ? themeColor.withValues(alpha: 0.5) : (isDark ? Colors.grey[700]! : Colors.grey.withValues(alpha: 0.2)), @@ -859,11 +850,7 @@ class _CollectNotesPageState extends State { child: Row( children: [ if (category == _category) - Icon( - Icons.check, - size: 16, - color: AppConstants.primaryColor, - ), + Icon(Icons.check, size: 16, color: themeColor), if (category == _category) const SizedBox(width: 8), Text( category, @@ -884,11 +871,7 @@ class _CollectNotesPageState extends State { if (!_categoryOptions.contains(_category) && _category != null && _category!.isNotEmpty) - Icon( - Icons.check, - size: 16, - color: AppConstants.primaryColor, - ), + Icon(Icons.check, size: 16, color: themeColor), if (!_categoryOptions.contains(_category) && _category != null && _category!.isNotEmpty) @@ -917,18 +900,11 @@ class _CollectNotesPageState extends State { child: Row( mainAxisSize: MainAxisSize.min, children: [ - Icon( - Icons.folder_outlined, - size: 18, - color: AppConstants.primaryColor, - ), + Icon(Icons.folder_outlined, size: 18, color: themeColor), const SizedBox(width: 4), Text( _category ?? '分类', - style: TextStyle( - fontSize: 14, - color: AppConstants.primaryColor, - ), + style: TextStyle(fontSize: 14, color: themeColor), ), Icon( Icons.arrow_drop_down, @@ -944,7 +920,7 @@ class _CollectNotesPageState extends State { ); } - Widget _buildContentInput(bool isDark) { + Widget _buildContentInput(bool isDark, Color themeColor) { return Container( constraints: const BoxConstraints(minHeight: 300), decoration: BoxDecoration( @@ -952,7 +928,7 @@ class _CollectNotesPageState extends State { borderRadius: BorderRadius.circular(12), border: Border.all( color: _contentFocusNode.hasFocus - ? AppConstants.primaryColor.withValues(alpha: 0.5) + ? themeColor.withValues(alpha: 0.5) : (isDark ? Colors.grey[700]! : Colors.grey.withValues(alpha: 0.2)), diff --git a/lib/views/footprint/footprint_page.dart b/lib/views/footprint/footprint_page.dart index b501600..7e5b0f3 100644 --- a/lib/views/footprint/footprint_page.dart +++ b/lib/views/footprint/footprint_page.dart @@ -100,6 +100,7 @@ class _FootprintPageState extends State try { // 从SQLite获取完整数据 final likedList = await HistoryController.getLikedHistory(); + final themeColor = _themeController.currentThemeColor; // 查找对应的诗词数据,优先使用存储的完整数据 Map poetryData; @@ -136,7 +137,9 @@ class _FootprintPageState extends State width: 40, height: 4, decoration: BoxDecoration( - color: Colors.grey[300], + color: _themeController.isDarkMode + ? Colors.grey[700] + : Colors.grey[300], borderRadius: BorderRadius.circular(2), ), ), @@ -146,17 +149,16 @@ class _FootprintPageState extends State padding: const EdgeInsets.all(16), child: Row( children: [ - Icon( - Icons.article, - color: AppConstants.primaryColor, - size: 24, - ), + Icon(Icons.article, color: themeColor, size: 24), const SizedBox(width: 8), - const Text( + Text( '诗词详情', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, + color: _themeController.isDarkMode + ? Colors.white + : Colors.black, ), ), const Spacer(), @@ -174,7 +176,9 @@ class _FootprintPageState extends State padding: const EdgeInsets.all(8), child: Icon( Icons.more_horiz, - color: Colors.grey[600], + color: _themeController.isDarkMode + ? Colors.grey[400] + : Colors.grey[600], size: 20, ), ), @@ -184,7 +188,9 @@ class _FootprintPageState extends State IconButton( onPressed: () => Navigator.of(context).pop(), icon: const Icon(Icons.close), - color: Colors.grey[600], + color: _themeController.isDarkMode + ? Colors.grey[400] + : Colors.grey[600], ), ], ), @@ -202,7 +208,7 @@ class _FootprintPageState extends State '精选诗句', poetryData['name'] ?? poetry.name, Icons.format_quote, - AppConstants.primaryColor, + themeColor, ), // 时间和标签 - 同一行 @@ -277,7 +283,7 @@ class _FootprintPageState extends State '译文/介绍', poetryData['introduce'], Icons.translate, - AppConstants.primaryColor, + themeColor, ), // 原文 - 单独一行 @@ -319,6 +325,7 @@ class _FootprintPageState extends State IconData icon, Color accentColor, ) { + final isDark = _themeController.isDarkMode; return Container( width: double.infinity, margin: const EdgeInsets.only(bottom: 12), @@ -361,9 +368,9 @@ class _FootprintPageState extends State padding: const EdgeInsets.all(12), child: Text( content, - style: const TextStyle( + style: TextStyle( fontSize: 15, - color: Colors.black87, + color: isDark ? Colors.white : Colors.black87, height: 1.5, ), ), @@ -405,27 +412,26 @@ class _FootprintPageState extends State Widget build(BuildContext context) { return Obx(() { final isDark = _themeController.isDarkMode; + final themeColor = _themeController.currentThemeColor; return Scaffold( backgroundColor: isDark ? const Color(0xFF1A1A1A) : Colors.grey[50], appBar: AppBar( title: const Text('点赞足迹'), - backgroundColor: isDark - ? const Color(0xFF2A2A2A) - : AppConstants.primaryColor, + backgroundColor: isDark ? const Color(0xFF2A2A2A) : themeColor, foregroundColor: Colors.white, elevation: 0, ), - body: _buildBody(isDark), + body: _buildBody(isDark, themeColor), ); }); } - Widget _buildBody(bool isDark) { + Widget _buildBody(bool isDark, Color themeColor) { if (_isLoading) { return Center( child: CircularProgressIndicator( valueColor: AlwaysStoppedAnimation( - isDark ? Colors.white : AppConstants.primaryColor, + isDark ? Colors.white : themeColor, ), ), ); @@ -453,7 +459,7 @@ class _FootprintPageState extends State ElevatedButton( onPressed: _loadLikedPoetry, style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: themeColor, foregroundColor: Colors.white, ), child: const Text('重试'), @@ -506,16 +512,14 @@ class _FootprintPageState extends State Icon( Icons.refresh, size: 20, - color: isDark ? Colors.white70 : AppConstants.primaryColor, + color: isDark ? Colors.white70 : themeColor, ), const SizedBox(width: 8), Text( '下拉刷新列表', style: TextStyle( fontSize: 14, - color: isDark - ? Colors.white70 - : AppConstants.primaryColor, + color: isDark ? Colors.white70 : themeColor, fontWeight: FontWeight.w500, ), ), @@ -537,7 +541,7 @@ class _FootprintPageState extends State itemCount: _likedPoetryList.length, itemBuilder: (context, index) { final poetry = _likedPoetryList[index]; - return _buildLikedPoetryCard(poetry, isDark); + return _buildLikedPoetryCard(poetry, isDark, themeColor); }, ), ), @@ -546,7 +550,11 @@ class _FootprintPageState extends State ); } - Widget _buildLikedPoetryCard(PoetryData poetry, bool isDark) { + Widget _buildLikedPoetryCard( + PoetryData poetry, + bool isDark, + Color themeColor, + ) { return Container( margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( @@ -587,20 +595,20 @@ class _FootprintPageState extends State decoration: BoxDecoration( gradient: LinearGradient( colors: [ - AppConstants.primaryColor.withValues(alpha: 0.1), - AppConstants.primaryColor.withValues(alpha: 0.05), + themeColor.withValues(alpha: 0.1), + themeColor.withValues(alpha: 0.05), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(12), border: Border.all( - color: AppConstants.primaryColor.withValues(alpha: 0.2), + color: themeColor.withValues(alpha: 0.2), width: 1, ), boxShadow: [ BoxShadow( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: themeColor.withValues(alpha: 0.1), blurRadius: 8, offset: const Offset(0, 2), ), @@ -611,11 +619,7 @@ class _FootprintPageState extends State children: [ Row( children: [ - Icon( - Icons.format_quote, - color: AppConstants.primaryColor, - size: 20, - ), + Icon(Icons.format_quote, color: themeColor, size: 20), const SizedBox(width: 8), Expanded( child: Text( @@ -623,7 +627,7 @@ class _FootprintPageState extends State style: TextStyle( fontSize: 12, fontWeight: FontWeight.w500, - color: AppConstants.primaryColor, + color: themeColor, ), ), ), @@ -702,7 +706,7 @@ class _FootprintPageState extends State icon: const Icon(Icons.visibility, size: 18), label: const Text('查看详情'), style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: themeColor, foregroundColor: Colors.white, elevation: 2, shape: RoundedRectangleBorder( diff --git a/lib/views/footprint/liked_poetry_manager.dart b/lib/views/footprint/liked_poetry_manager.dart index 2f30c2d..6cd5569 100644 --- a/lib/views/footprint/liked_poetry_manager.dart +++ b/lib/views/footprint/liked_poetry_manager.dart @@ -14,6 +14,8 @@ import '../../../config/app_config.dart'; import '../../../controllers/history_controller.dart'; import '../../../utils/http/poetry_api.dart'; import '../../../services/network_listener_service.dart'; +import '../../../services/get/theme_controller.dart'; +import 'package:get/get.dart'; import '../home/set/home_components.dart'; /// 点赞诗词管理器 @@ -295,6 +297,7 @@ class _LikedPoetryManagerState extends State bool _isLoading = false; String _errorMessage = ''; StreamSubscription? _networkSubscription; + final ThemeController _themeController = Get.find(); @override void initState() { @@ -393,14 +396,21 @@ class _LikedPoetryManagerState extends State @override Widget build(BuildContext context) { - return _buildLikedPoetryList(); + return Obx(() { + return _buildLikedPoetryList(); + }); } Widget _buildLikedPoetryList() { + final themeColor = _themeController.currentThemeColor; + final isDark = _themeController.isDarkMode; + if (_isLoading) { - return const Center( + return Center( child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(AppConstants.primaryColor), + valueColor: AlwaysStoppedAnimation( + isDark ? Colors.white : themeColor, + ), ), ); } @@ -420,7 +430,7 @@ class _LikedPoetryManagerState extends State ElevatedButton( onPressed: _loadLikedPoetry, style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: themeColor, foregroundColor: Colors.white, ), child: const Text('重试'), @@ -435,16 +445,26 @@ class _LikedPoetryManagerState extends State child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon(Icons.favorite_border, size: 64, color: Colors.grey[400]), + Icon( + Icons.favorite_border, + size: 64, + color: isDark ? Colors.grey[600] : Colors.grey[400], + ), const SizedBox(height: 16), Text( '暂无点赞记录', - style: TextStyle(fontSize: 16, color: Colors.grey[600]), + style: TextStyle( + fontSize: 16, + color: isDark ? Colors.grey[400] : Colors.grey[600], + ), ), const SizedBox(height: 8), Text( '去主页点赞喜欢的诗词吧', - style: TextStyle(fontSize: 14, color: Colors.grey[500]), + style: TextStyle( + fontSize: 14, + color: isDark ? Colors.grey[500] : Colors.grey[500], + ), ), ], ), @@ -464,44 +484,61 @@ class _LikedPoetryManagerState extends State itemCount: _likedPoetryList.length + 1, itemBuilder: (context, index) { if (index == _likedPoetryList.length) { - return _buildBottomIndicator(); + return _buildBottomIndicator(isDark); } final poetry = _likedPoetryList[index]; - return _buildLikedPoetryCard(poetry); + return _buildLikedPoetryCard(poetry, themeColor, isDark); }, ), ); } - Widget _buildBottomIndicator() { + Widget _buildBottomIndicator(bool isDark) { return Container( padding: const EdgeInsets.symmetric(vertical: 24), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Container(width: 40, height: 1, color: Colors.grey[300]), + Container( + width: 40, + height: 1, + color: isDark ? Colors.grey[700] : Colors.grey[300], + ), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Text( '到底了', - style: TextStyle(fontSize: 12, color: Colors.grey[400]), + style: TextStyle( + fontSize: 12, + color: isDark ? Colors.grey[500] : Colors.grey[400], + ), ), ), - Container(width: 40, height: 1, color: Colors.grey[300]), + Container( + width: 40, + height: 1, + color: isDark ? Colors.grey[700] : Colors.grey[300], + ), ], ), ); } - Widget _buildLikedPoetryCard(PoetryData poetry) { + Widget _buildLikedPoetryCard( + PoetryData poetry, + Color themeColor, + bool isDark, + ) { return Container( margin: const EdgeInsets.only(bottom: 8), decoration: BoxDecoration( - color: Colors.white, + color: isDark ? const Color(0xFF2A2A2A) : Colors.white, borderRadius: BorderRadius.circular(8), boxShadow: [ BoxShadow( - color: Colors.black.withValues(alpha: 0.03), + color: isDark + ? Colors.black.withValues(alpha: 0.3) + : Colors.black.withValues(alpha: 0.03), blurRadius: 4, offset: const Offset(0, 1), ), @@ -519,15 +556,15 @@ class _LikedPoetryManagerState extends State decoration: BoxDecoration( gradient: LinearGradient( colors: [ - AppConstants.primaryColor.withValues(alpha: 0.1), - AppConstants.primaryColor.withValues(alpha: 0.05), + themeColor.withValues(alpha: 0.1), + themeColor.withValues(alpha: 0.05), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(6), border: Border.all( - color: AppConstants.primaryColor.withValues(alpha: 0.2), + color: themeColor.withValues(alpha: 0.2), width: 1, ), ), @@ -537,18 +574,14 @@ class _LikedPoetryManagerState extends State children: [ Row( children: [ - Icon( - Icons.format_quote, - color: AppConstants.primaryColor, - size: 14, - ), + Icon(Icons.format_quote, color: themeColor, size: 14), const SizedBox(width: 4), Text( '精选诗句', style: TextStyle( fontSize: 10, fontWeight: FontWeight.w500, - color: AppConstants.primaryColor, + color: themeColor, ), ), ], @@ -556,10 +589,10 @@ class _LikedPoetryManagerState extends State const SizedBox(height: 4), Text( poetry.name, - style: const TextStyle( + style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, - color: Colors.black87, + color: isDark ? Colors.white : Colors.black87, height: 1.2, ), ), @@ -573,7 +606,10 @@ class _LikedPoetryManagerState extends State padding: const EdgeInsets.fromLTRB(8, 4, 8, 2), child: Text( "出处:${poetry.url}", - style: TextStyle(fontSize: 11, color: Colors.grey[600]), + style: TextStyle( + fontSize: 11, + color: isDark ? Colors.grey[400] : Colors.grey[600], + ), overflow: TextOverflow.ellipsis, maxLines: 1, ), @@ -613,7 +649,7 @@ class _LikedPoetryManagerState extends State icon: const Icon(Icons.visibility, size: 14), label: const Text('查看详情', style: TextStyle(fontSize: 12)), style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: themeColor, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(6), diff --git a/lib/views/footprint/local_jilu.dart b/lib/views/footprint/local_jilu.dart index 0375590..26ee8ea 100644 --- a/lib/views/footprint/local_jilu.dart +++ b/lib/views/footprint/local_jilu.dart @@ -78,17 +78,18 @@ class _LocalNotesListState extends State { Widget build(BuildContext context) { return Obx(() { final isDark = _themeController.isDarkMode; + final themeColor = _themeController.currentThemeColor; if (_isLoadingNotes && _notes.isEmpty) { return Center( child: CircularProgressIndicator( - color: isDark ? Colors.white : AppConstants.primaryColor, + color: isDark ? Colors.white : themeColor, ), ); } if (_notes.isEmpty) { - return _buildEmptyNotes(isDark); + return _buildEmptyNotes(isDark, themeColor); } return RefreshIndicator( @@ -107,7 +108,7 @@ class _LocalNotesListState extends State { return _buildBottomIndicator(isDark); } final note = _notes[index]; - return _buildNoteCard(note, isDark); + return _buildNoteCard(note, isDark, themeColor); }, ), ); @@ -145,7 +146,7 @@ class _LocalNotesListState extends State { ); } - Widget _buildEmptyNotes(bool isDark) { + Widget _buildEmptyNotes(bool isDark, Color themeColor) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -176,7 +177,7 @@ class _LocalNotesListState extends State { ); } - Widget _buildNoteCard(Map note, bool isDark) { + Widget _buildNoteCard(Map note, bool isDark, Color themeColor) { final title = note['title'] as String? ?? ''; final content = note['content'] as String? ?? ''; final timeStr = note['time'] as String? ?? ''; @@ -272,7 +273,7 @@ class _LocalNotesListState extends State { vertical: 2, ), decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues( + color: themeColor.withValues( alpha: 0.1, ), borderRadius: BorderRadius.circular(10), @@ -281,7 +282,7 @@ class _LocalNotesListState extends State { category, style: TextStyle( fontSize: 10, - color: AppConstants.primaryColor, + color: themeColor, ), ), ), @@ -292,7 +293,7 @@ class _LocalNotesListState extends State { child: Icon( Icons.lock, size: 16, - color: AppConstants.primaryColor, + color: themeColor, ), ), GestureDetector( @@ -305,7 +306,7 @@ class _LocalNotesListState extends State { : Icons.push_pin_outlined, size: 16, color: isPinned - ? AppConstants.primaryColor + ? themeColor : (isDark ? Colors.grey[500] : Colors.grey[400]), @@ -418,7 +419,7 @@ class _LocalNotesListState extends State { Icon( Icons.lock, size: 28, - color: AppConstants.primaryColor, + color: themeColor, ), const SizedBox(width: 12), Column( @@ -430,7 +431,7 @@ class _LocalNotesListState extends State { '已锁定', style: TextStyle( fontSize: 14, - color: AppConstants.primaryColor, + color: themeColor, fontWeight: FontWeight.w500, ), ), diff --git a/lib/views/home/care/care-page.dart b/lib/views/home/care/care-page.dart new file mode 100644 index 0000000..01b69fe --- /dev/null +++ b/lib/views/home/care/care-page.dart @@ -0,0 +1,478 @@ +/// 时间: 2026-04-02 +/// 功能: 关怀页面 +/// 介绍: 简约大字风格的关怀功能页面 +/// 最新变化: 2026-04-02 添加多个按钮和文本描述区域 + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import '../../../services/get/theme_controller.dart'; +import '../../../services/get/care_controller.dart'; + +class CarePage extends StatefulWidget { + const CarePage({super.key}); + + @override + State createState() => _CarePageState(); +} + +class _CarePageState extends State { + final CareController _careController = Get.find(); + bool _readAloudEnabled = false; + final List _options = ['诗词', '出处', '译文', '更多', '原文', '问候语']; + + @override + Widget build(BuildContext context) { + final themeController = Get.find(); + final isDark = themeController.isDarkModeRx.value; + final primaryColor = themeController.currentThemeColor; + + return Scaffold( + backgroundColor: isDark ? const Color(0xFF121212) : Colors.white, + appBar: AppBar( + title: Text( + '关怀', + style: TextStyle( + color: isDark ? Colors.white : primaryColor, + fontWeight: FontWeight.bold, + ), + ), + backgroundColor: isDark ? const Color(0xFF1A1A1A) : Colors.white, + elevation: 0, + leading: IconButton( + icon: Icon( + Icons.arrow_back, + color: isDark ? Colors.white : primaryColor, + ), + onPressed: () => Navigator.pop(context), + ), + actions: [ + IconButton( + icon: Icon( + Icons.info_outline, + color: isDark ? Colors.white : primaryColor, + ), + onPressed: () { + showDialog( + context: context, + builder: (context) => AlertDialog( + backgroundColor: isDark + ? const Color(0xFF2A2A2A) + : Colors.white, + title: Text( + '功能说明', + style: TextStyle( + color: isDark ? Colors.white : Colors.black87, + fontWeight: FontWeight.bold, + ), + ), + content: Text( + '该功能处于开发状态,限时免费使用\n待后续开发完成后,使用需付费激活\n其他功能不受影响。', + style: TextStyle( + color: isDark ? Colors.grey[300] : Colors.grey[700], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('确定', style: TextStyle(color: primaryColor)), + ), + ], + ), + ); + }, + ), + ], + ), + body: SingleChildScrollView( + padding: const EdgeInsets.all(32), + child: Column( + children: [ + Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon(Icons.people, size: 80, color: primaryColor), + const SizedBox(width: 32), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '关怀', + style: TextStyle( + fontSize: 48, + fontWeight: FontWeight.bold, + color: isDark ? Colors.white : Colors.black87, + ), + ), + const SizedBox(height: 16), + Text( + '用心呵护每一位用户', + style: TextStyle( + fontSize: 18, + color: isDark ? Colors.grey[400] : Colors.grey[600], + ), + ), + ], + ), + ], + ), + ), + const SizedBox(height: 48), + _buildCareModeToggle(isDark, primaryColor), + const SizedBox(height: 24), + _buildUserTypeSelector(isDark, primaryColor), + const SizedBox(height: 24), + _buildPinyinToggle(isDark, primaryColor), + const SizedBox(height: 24), + _buildMultiSelectOptions(isDark, primaryColor), + const SizedBox(height: 24), + _buildDescriptionArea(isDark), + ], + ), + ), + ); + } + + Widget _buildCareModeToggle(bool isDark, Color primaryColor) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), + decoration: BoxDecoration( + color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100], + borderRadius: BorderRadius.circular(16), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '关怀模式', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: isDark ? Colors.white : Colors.black87, + ), + ), + Obx( + () => Switch( + value: _careController.isCareModeEnabled, + onChanged: (value) => _careController.toggleCareMode(), + activeColor: primaryColor, + ), + ), + ], + ), + ); + } + + Widget _buildUserTypeSelector(bool isDark, Color primaryColor) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), + decoration: BoxDecoration( + color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100], + borderRadius: BorderRadius.circular(16), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '用户类型', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: isDark ? Colors.white : Colors.black87, + ), + ), + const SizedBox(height: 16), + Row( + children: [ + Expanded( + child: _buildUserTypeButton( + '儿童', + _careController.userType == '儿童', + isDark, + primaryColor, + ), + ), + const SizedBox(width: 16), + Expanded( + child: _buildUserTypeButton( + '学生', + _careController.userType == '学生', + isDark, + primaryColor, + ), + ), + ], + ), + const SizedBox(height: 16), + Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: isDark ? const Color(0xFF3A3A3A) : Colors.white, + borderRadius: BorderRadius.circular(12), + ), + child: Obx( + () => Text( + _careController.userType == '儿童' + ? '儿童模式:大字体、简单界面、拼音辅助,适合低龄儿童使用。界面更加卡通化,内容简单易懂,帮助儿童轻松学习诗词。' + : '学生模式:适中字体、学习辅助、诗词解析,适合学生群体使用。提供详细的诗词注释、背景知识,助力学生深入理解古典文学。', + style: TextStyle( + fontSize: 14, + height: 1.5, + color: isDark ? Colors.grey[300] : Colors.grey[700], + ), + ), + ), + ), + ], + ), + ); + } + + Widget _buildUserTypeButton( + String label, + bool isSelected, + bool isDark, + Color primaryColor, + ) { + return GestureDetector( + onTap: () => _careController.setUserType(label), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 16), + decoration: BoxDecoration( + color: isSelected + ? primaryColor + : (isDark ? const Color(0xFF3A3A3A) : Colors.white), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: isSelected ? primaryColor : Colors.transparent, + width: 2, + ), + ), + child: Center( + child: Text( + label, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: isSelected + ? Colors.white + : (isDark ? Colors.white : Colors.black87), + ), + ), + ), + ), + ); + } + + Widget _buildPinyinToggle(bool isDark, Color primaryColor) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), + decoration: BoxDecoration( + color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100], + borderRadius: BorderRadius.circular(16), + ), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '拼音显示', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: isDark ? Colors.white : Colors.black87, + ), + ), + Obx( + () => Switch( + value: _careController.pinyinEnabled, + onChanged: (value) => _careController.setPinyinEnabled(value), + activeColor: primaryColor, + ), + ), + ], + ), + const SizedBox(height: 16), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Text( + '朗读', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: isDark ? Colors.white : Colors.black87, + ), + ), + const SizedBox(width: 8), + IconButton( + icon: Icon( + Icons.info_outline, + color: isDark ? Colors.grey[400] : Colors.grey[600], + size: 20, + ), + onPressed: () { + showDialog( + context: context, + builder: (context) => AlertDialog( + backgroundColor: isDark + ? const Color(0xFF2A2A2A) + : Colors.white, + title: Text( + '功能说明', + style: TextStyle( + color: isDark ? Colors.white : Colors.black87, + fontWeight: FontWeight.bold, + ), + ), + content: Text( + '你使用的设备暂不支持朗读功能\n 等待上游厂商适配TTS.', + style: TextStyle( + color: isDark + ? Colors.grey[300] + : Colors.grey[700], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text( + '确定', + style: TextStyle(color: primaryColor), + ), + ), + ], + ), + ); + }, + ), + ], + ), + Switch( + value: false, + onChanged: null, + activeColor: isDark ? Colors.grey[700] : Colors.grey[400], + inactiveTrackColor: isDark + ? Colors.grey[800] + : Colors.grey[300], + ), + ], + ), + ], + ), + ); + } + + Widget _buildMultiSelectOptions(bool isDark, Color primaryColor) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16), + decoration: BoxDecoration( + color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100], + borderRadius: BorderRadius.circular(16), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '显示选项', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: isDark ? Colors.white : Colors.black87, + ), + ), + const SizedBox(height: 16), + Obx( + () => Wrap( + spacing: 12, + runSpacing: 12, + children: _options.map((option) { + final isSelected = _careController.selectedOptions.contains( + option, + ); + final isPoetry = option == '诗词'; + return GestureDetector( + onTap: isPoetry + ? null + : () => _careController.toggleOption(option), + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 12, + ), + decoration: BoxDecoration( + color: isSelected + ? primaryColor + : (isDark ? const Color(0xFF3A3A3A) : Colors.white), + borderRadius: BorderRadius.circular(12), + border: Border.all( + color: isSelected ? primaryColor : Colors.transparent, + width: 2, + ), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (isSelected) + Icon(Icons.check, color: Colors.white, size: 20), + if (isSelected) const SizedBox(width: 8), + Text( + option, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: isSelected + ? Colors.white + : (isDark ? Colors.white : Colors.black87), + ), + ), + ], + ), + ), + ); + }).toList(), + ), + ), + ], + ), + ); + } + + Widget _buildDescriptionArea(bool isDark) { + return Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100], + borderRadius: BorderRadius.circular(16), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '功能说明', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: isDark ? Colors.white : Colors.black87, + ), + ), + const SizedBox(height: 12), + Text( + '关怀模式为儿童和学生用户提供更加友好的界面体验。\n\n' + '开启关怀模式后,应用将根据选择的用户类型自动调整界面显示。', + style: TextStyle( + fontSize: 16, + height: 1.6, + color: isDark ? Colors.grey[300] : Colors.grey[700], + ), + ), + ], + ), + ); + } +} diff --git a/lib/views/home/care/care_poetry_page.dart b/lib/views/home/care/care_poetry_page.dart new file mode 100644 index 0000000..544d2e1 --- /dev/null +++ b/lib/views/home/care/care_poetry_page.dart @@ -0,0 +1,512 @@ +/// 时间: 2026-04-02 +/// 功能: 关怀模式诗词页面 +/// 介绍: 关怀模式下显示的诗词页面,根据关怀设置显示不同内容 +/// 最新变化: 2026-04-02 初始创建 + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import '../../../services/get/home_controller.dart'; +import '../../../services/get/theme_controller.dart'; +import '../../../services/get/care_controller.dart'; +import '../../../constants/app_constants.dart'; +import '../home_part.dart'; +import 'care_widgets.dart'; +import 'pinyin_helper.dart'; + +class CarePoetryPage extends StatefulWidget { + const CarePoetryPage({super.key}); + + @override + State createState() => _CarePoetryPageState(); +} + +class _CarePoetryPageState extends State + with SingleTickerProviderStateMixin { + String _getTimeOfDayGreeting() { + final hour = DateTime.now().hour; + if (hour >= 5 && hour < 7) { + return '清晨了,呼吸新鲜空气'; + } else if (hour >= 7 && hour < 9) { + return '早上好,元气满满'; + } else if (hour >= 9 && hour < 12) { + return '上午好,努力工作'; + } else if (hour >= 12 && hour < 14) { + return '中午了,吃顿好的'; + } else if (hour >= 14 && hour < 17) { + return '下午了,喝杯咖啡'; + } else if (hour >= 17 && hour < 19) { + return '傍晚了,休息一下'; + } else if (hour >= 19 && hour < 22) { + return '晚上好,放松身心'; + } else { + return '深夜了,注意身体'; + } + } + + late AnimationController _animationController; + late Animation _fadeAnimation; + + @override + void initState() { + super.initState(); + _animationController = AnimationController( + duration: const Duration(milliseconds: 500), + vsync: this, + ); + _fadeAnimation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation(parent: _animationController, curve: Curves.easeOut), + ); + _animationController.forward(); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final homeController = Get.find(); + final themeController = Get.find(); + final careController = Get.find(); + + return Obx(() { + final isDark = themeController.isDarkModeRx.value; + final primaryColor = themeController.currentThemeColor; + final poetryData = homeController.poetryData.value; + + if (poetryData == null) { + return const Center(child: CircularProgressIndicator()); + } + + // 当诗词数据变化时,重新播放动画 + _animationController.reset(); + _animationController.forward(); + + return Scaffold( + backgroundColor: isDark ? const Color(0xFF121212) : Colors.grey[50], + body: SafeArea( + child: GestureDetector( + onTap: () async { + try { + await homeController.loadNextPoetry(); + } catch (e) { + print('加载诗词失败: $e'); + } + }, + child: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: FadeTransition( + opacity: _fadeAnimation, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // 关怀模式开关 + CarePageHeaderToggle(isDark: isDark), + const SizedBox(height: 16), + // 问候语bar + if (careController.selectedOptions.contains('问候语')) + Container( + width: double.infinity, + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 12, + ), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [primaryColor.withAlpha(204), primaryColor], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + children: [ + Icon(Icons.wb_sunny, color: Colors.white, size: 20), + const SizedBox(width: 8), + Expanded( + child: Text( + _getTimeOfDayGreeting(), + style: const TextStyle( + color: Colors.white, + fontSize: 14, + fontWeight: FontWeight.w500, + ), + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + ), + ], + ), + ), + if (careController.selectedOptions.contains('问候语')) + const SizedBox(height: 16), + // 出处 + if (careController.selectedOptions.contains('出处')) + _buildPoetrySource(poetryData, isDark, primaryColor), + if (careController.selectedOptions.contains('出处')) + const SizedBox(height: 24), + if (!careController.selectedOptions.contains('问候语') && + !careController.selectedOptions.contains('出处')) + const SizedBox(height: 24), + // 诗词标题 + if (careController.selectedOptions.contains('诗词')) + _buildPoetryTitle(poetryData, isDark, primaryColor), + + const SizedBox(height: 24), + + // 诗词内容 + if (careController.selectedOptions.contains('诗词')) + GestureDetector( + onTap: () async { + try { + await homeController.loadNextPoetry(); + } catch (e) { + print('加载诗词失败: $e'); + } + }, + child: _buildPoetryContent( + poetryData, + isDark, + primaryColor, + ), + ), + + const SizedBox(height: 24), + + // 原文 + if (careController.selectedOptions.contains('原文')) + _buildPoetryOriginal(poetryData, isDark, primaryColor), + + if (careController.selectedOptions.contains('原文')) + const SizedBox(height: 24), + + const SizedBox(height: 24), + + // 译文 + if (careController.selectedOptions.contains('译文')) + _buildPoetryTranslation(poetryData, isDark, primaryColor), + + const SizedBox(height: 24), + + // 更多 + if (careController.selectedOptions.contains('更多')) + _buildPoetryMore(poetryData, isDark, primaryColor), + + const SizedBox(height: 48), + ], + ), + ), + ), + ), + ), + ); + }); + } + + Widget _buildPoetryTitle( + dynamic poetryData, + bool isDark, + Color primaryColor, + ) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100], + borderRadius: BorderRadius.circular(12), + ), + child: Text( + poetryData.name ?? '未知标题', + style: TextStyle( + fontSize: 28, + fontWeight: FontWeight.bold, + color: primaryColor, + ), + textAlign: TextAlign.center, + ), + ); + } + + Widget _buildPoetryContent( + dynamic poetryData, + bool isDark, + Color primaryColor, + ) { + final themeController = Get.find(); + final careController = Get.find(); + final accentColor = themeController.currentAccentColor; + final content = poetryData.name ?? ''; + final lines = content.split('\n'); + final showPinyin = careController.pinyinEnabled; + + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: isDark + ? accentColor.withOpacity(0.2) + : accentColor.withOpacity(0.1), + borderRadius: BorderRadius.circular(12), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: lines.asMap().entries.map((entry) { + int index = entry.key; + String line = entry.value; + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Column( + children: [ + if (showPinyin && line.trim().isNotEmpty) + Wrap( + alignment: WrapAlignment.center, + children: PinyinHelper.convertToCharPinyinList(line) + .asMap() + .entries + .map((charEntry) { + int charIndex = charEntry.key; + var item = charEntry.value; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: AnimatedOpacity( + opacity: 1.0, + duration: Duration( + milliseconds: 300 + charIndex * 100, + ), + curve: Curves.easeOut, + child: Column( + children: [ + Text( + item['pinyin'] ?? '', + style: TextStyle( + fontSize: 12, + color: isDark + ? Colors.grey[400] + : Colors.grey[600], + height: 1.2, + ), + textAlign: TextAlign.center, + ), + Text( + item['char'] ?? '', + style: TextStyle( + fontSize: 20, + color: primaryColor, + height: 1.6, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ); + }) + .toList(), + ), + if (!showPinyin || line.trim().isEmpty) + Wrap( + alignment: WrapAlignment.center, + children: line.split('').asMap().entries.map(( + charEntry, + ) { + int charIndex = charEntry.key; + String char = charEntry.value; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: AnimatedOpacity( + opacity: 1.0, + duration: Duration( + milliseconds: 300 + charIndex * 100, + ), + curve: Curves.easeOut, + child: Text( + char, + style: TextStyle( + fontSize: 20, + color: primaryColor, + height: 1.6, + ), + textAlign: TextAlign.center, + ), + ), + ); + }).toList(), + ), + ], + ), + ); + }).toList(), + ), + ); + } + + Widget _buildPoetrySource( + dynamic poetryData, + bool isDark, + Color primaryColor, + ) { + final url = poetryData.url ?? '未知作者'; + + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100], + borderRadius: BorderRadius.circular(12), + ), + child: Text( + url, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: primaryColor, + ), + textAlign: TextAlign.center, + ), + ); + } + + Widget _buildPoetryTranslation( + dynamic poetryData, + bool isDark, + Color primaryColor, + ) { + final translation = poetryData.introduce ?? '暂无译文'; + + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100], + borderRadius: BorderRadius.circular(12), + ), + child: Text( + translation, + style: TextStyle( + fontSize: 16, + color: isDark ? Colors.grey[300] : Colors.grey[700], + height: 1.6, + ), + textAlign: TextAlign.center, + ), + ); + } + + Widget _buildPoetryMore(dynamic poetryData, bool isDark, Color primaryColor) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100], + borderRadius: BorderRadius.circular(12), + ), + child: Column( + children: [ + Text( + '更多信息', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: primaryColor, + ), + ), + const SizedBox(height: 12), + Text( + '诗词解析、背景知识等内容将在此显示', + style: TextStyle( + fontSize: 14, + color: isDark ? Colors.grey[300] : Colors.grey[700], + ), + textAlign: TextAlign.center, + ), + ], + ), + ); + } + + Widget _buildPoetryOriginal( + dynamic poetryData, + bool isDark, + Color primaryColor, + ) { + final original = poetryData.drtime ?? '暂无原文'; + final careController = Get.find(); + final showPinyin = careController.pinyinEnabled; + final lines = original.split('\n'); + + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: isDark ? const Color(0xFF2A2A2A) : Colors.grey[100], + borderRadius: BorderRadius.circular(12), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: lines.asMap().entries.map((entry) { + int index = entry.key; + String line = entry.value; + return Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Column( + children: [ + if (showPinyin && line.trim().isNotEmpty) + Wrap( + alignment: WrapAlignment.center, + children: PinyinHelper.convertToCharPinyinList(line) + .asMap() + .entries + .map((charEntry) { + int charIndex = charEntry.key; + var item = charEntry.value; + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: AnimatedOpacity( + opacity: 1.0, + duration: Duration( + milliseconds: 300 + charIndex * 100, + ), + curve: Curves.easeOut, + child: Column( + children: [ + Text( + item['pinyin'] ?? '', + style: TextStyle( + fontSize: 12, + color: isDark + ? Colors.grey[400] + : Colors.grey[600], + height: 1.2, + ), + textAlign: TextAlign.center, + ), + Text( + item['char'] ?? '', + style: TextStyle( + fontSize: 16, + color: primaryColor, + height: 1.6, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ); + }) + .toList(), + ), + if (!showPinyin || line.trim().isEmpty) + Text( + line, + style: TextStyle( + fontSize: 16, + color: primaryColor, + height: 1.6, + ), + textAlign: TextAlign.center, + ), + ], + ), + ); + }).toList(), + ), + ); + } +} diff --git a/lib/views/home/care/care_widgets.dart b/lib/views/home/care/care_widgets.dart new file mode 100644 index 0000000..ccffcdc --- /dev/null +++ b/lib/views/home/care/care_widgets.dart @@ -0,0 +1,171 @@ +/// 时间: 2026-04-02 +/// 功能: 关怀模式相关组件 +/// 介绍: 包含关怀按钮和开关的UI组件 +/// 最新变化: 2026-04-02 初始创建 + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import '../../../services/get/theme_controller.dart'; +import '../../../services/get/care_controller.dart'; +import 'care-page.dart'; + +/// 关怀按钮组件 +class CareButton extends StatelessWidget { + const CareButton({super.key, required this.onTap, required this.isDark}); + + final VoidCallback onTap; + final bool isDark; + + @override + Widget build(BuildContext context) { + final themeController = Get.find(); + final primaryColor = themeController.currentThemeColor; + + return GestureDetector( + onTap: onTap, + child: Container( + width: 44, + height: 44, + decoration: BoxDecoration( + color: isDark ? const Color(0xFF2A2A2A) : Colors.white, + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: Colors.black.withAlpha(isDark ? 40 : 20), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Center(child: Icon(Icons.people, color: primaryColor, size: 24)), + ), + ); + } +} + +/// 关怀模式开关组件 +class CareModeToggle extends StatelessWidget { + const CareModeToggle({ + super.key, + required this.isEnabled, + required this.onToggle, + required this.isDark, + }); + + final bool isEnabled; + final VoidCallback onToggle; + final bool isDark; + + @override + Widget build(BuildContext context) { + final themeController = Get.find(); + final primaryColor = themeController.currentThemeColor; + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + margin: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: isDark ? const Color(0xFF2A2A2A) : Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withAlpha(isDark ? 40 : 20), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Icon(Icons.people, color: primaryColor, size: 20), + const SizedBox(width: 12), + GestureDetector( + onTap: () => Get.to(() => const CarePage()), + child: Text( + '关怀', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: isDark ? Colors.white : Colors.black, + ), + ), + ), + ], + ), + Switch( + value: isEnabled, + onChanged: (_) => onToggle(), + activeColor: primaryColor, + inactiveTrackColor: isDark ? Colors.grey[700] : Colors.grey[300], + ), + ], + ), + ); + } +} + +/// 关怀模式页面顶部开关组件 +class CarePageHeaderToggle extends StatelessWidget { + const CarePageHeaderToggle({super.key, required this.isDark}); + + final bool isDark; + + @override + Widget build(BuildContext context) { + final themeController = Get.find(); + final careController = Get.find(); + final primaryColor = themeController.currentThemeColor; + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + margin: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: isDark ? const Color(0xFF2A2A2A) : Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withAlpha(isDark ? 40 : 20), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Icon(Icons.people, color: primaryColor, size: 20), + const SizedBox(width: 12), + GestureDetector( + onTap: () => Get.to(() => const CarePage()), + child: Text( + '关怀模式', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: isDark ? Colors.white : Colors.black, + ), + ), + ), + ], + ), + Obx( + () => Switch( + value: careController.isCareModeEnabled, + onChanged: (value) { + // 关闭关怀模式并返回正常页面 + careController.toggleCareMode(); + }, + activeColor: primaryColor, + inactiveTrackColor: isDark ? Colors.grey[700] : Colors.grey[300], + ), + ), + ], + ), + ); + } +} diff --git a/lib/views/home/care/pinyin_helper.dart b/lib/views/home/care/pinyin_helper.dart new file mode 100644 index 0000000..befb092 --- /dev/null +++ b/lib/views/home/care/pinyin_helper.dart @@ -0,0 +1,79 @@ +/// 时间: 2026-04-02 +/// 功能: 拼音处理辅助类 +/// 介绍: 使用pinyin库为汉字生成带音调的拼音 +/// 最新变化: 2026-04-02 修正API使用方式,避免递归调用 + +import 'package:pinyin/pinyin.dart' as pinyin; + +class PinyinHelper { + /// 将汉字转换为带音调的拼音 + static String convertToPinyin(String text) { + if (text.isEmpty) return ''; + + try { + // 使用pinyin库将汉字转换为拼音 + return pinyin.PinyinHelper.getPinyin( + text, + separator: ' ', + format: pinyin.PinyinFormat.WITH_TONE_MARK, + ); + } catch (e) { + // 无法转换时返回空字符串 + return ''; + } + } + + /// 为诗词内容生成拼音 + static String generatePoetryPinyin(String content) { + if (content.isEmpty) return ''; + + // 按行分割诗词 + List lines = content.split('\n'); + List pinyinLines = []; + + // 为每行生成拼音 + for (String line in lines) { + if (line.trim().isNotEmpty) { + String linePinyin = convertToPinyin(line); + pinyinLines.add(linePinyin); + } else { + pinyinLines.add(''); + } + } + + return pinyinLines.join('\n'); + } + + /// 将字符串转换为每个汉字及其对应的拼音的列表 + static List> convertToCharPinyinList(String text) { + if (text.isEmpty) return []; + + List> result = []; + + try { + // 为每个字符生成拼音 + for (int i = 0; i < text.length; i++) { + String char = text[i]; + String charPinyin = ''; + + try { + charPinyin = pinyin.PinyinHelper.getPinyin( + char, + separator: ' ', + format: pinyin.PinyinFormat.WITH_TONE_MARK, + ); + } catch (e) { + // 无法转换时使用空字符串 + charPinyin = ''; + } + + result.add({'char': char, 'pinyin': charPinyin}); + } + } catch (e) { + // 发生错误时返回空列表 + return []; + } + + return result; + } +} diff --git a/lib/views/home/home_page.dart b/lib/views/home/home_page.dart index 414c23b..e60117e 100644 --- a/lib/views/home/home_page.dart +++ b/lib/views/home/home_page.dart @@ -14,6 +14,9 @@ import 'home_part.dart'; import 'set/home_components.dart'; import 'set/home-load.dart'; import 'set/home-set.dart'; +import '../../services/get/care_controller.dart'; +import 'care/care_widgets.dart'; +import 'care/care_poetry_page.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); @@ -22,23 +25,31 @@ class HomePage extends StatefulWidget { State createState() => _HomePageState(); } -class _HomePageState extends State { +class _HomePageState extends State + with SingleTickerProviderStateMixin { final GlobalKey repaintKey = GlobalKey(); final SecondaryButtonsManager _secondaryButtonsManager = SecondaryButtonsManager(); final FloatingButtonsVisibilityManager _floatingButtonsVisibilityManager = FloatingButtonsVisibilityManager(); + final CareController _careController = Get.put(CareController()); + late AnimationController _animationController; @override void initState() { super.initState(); _secondaryButtonsManager.init(); _floatingButtonsVisibilityManager.init(); + _animationController = AnimationController( + duration: const Duration(milliseconds: 300), + vsync: this, + ); } @override void dispose() { _floatingButtonsVisibilityManager.dispose(); + _animationController.dispose(); super.dispose(); } @@ -47,12 +58,40 @@ class _HomePageState extends State { Get.lazyPut(() => HomeController()); final controller = Get.find(); final themeController = Get.find(); + final careController = Get.find(); return Obx(() { final isDark = themeController.isDarkModeRx.value; - return Scaffold( - backgroundColor: isDark ? const Color(0xFF121212) : Colors.grey[50], - body: SafeArea(child: _buildBody(controller, isDark)), + + // 触发动画 + if (_animationController.status != AnimationStatus.forward) { + _animationController.forward(from: 0); + } + + // 关怀模式开启时显示关怀页面,添加过渡动画 + if (careController.isCareModeEnabled) { + return FadeTransition( + opacity: Tween(begin: 0, end: 1).animate( + CurvedAnimation( + parent: _animationController, + curve: Curves.easeInOut, + ), + ), + child: const CarePoetryPage(), + ); + } + + return FadeTransition( + opacity: Tween(begin: 0, end: 1).animate( + CurvedAnimation( + parent: _animationController, + curve: Curves.easeInOut, + ), + ), + child: Scaffold( + backgroundColor: isDark ? const Color(0xFF121212) : Colors.grey[50], + body: SafeArea(child: _buildBody(controller, isDark)), + ), ); }); } @@ -113,6 +152,30 @@ class _HomePageState extends State { ), ), ), + // 关怀按钮 - 左上角 + Positioned( + top: 8, + left: 16, + child: CareButton( + onTap: _careController.toggleCareButtonVisibility, + isDark: isDark, + ), + ), + // 关怀模式开关 + Obx( + () => _careController.isCareButtonVisible.value + ? Positioned( + top: 60, + left: 16, + right: 16, + child: CareModeToggle( + isEnabled: _careController.isCareModeEnabled, + onToggle: _careController.toggleCareMode, + isDark: isDark, + ), + ) + : const SizedBox.shrink(), + ), // 收起/恢复按钮 - 右上角(与下方分享按钮对齐) Positioned( top: 8, diff --git a/lib/views/home/home_part.dart b/lib/views/home/home_part.dart index 78f7e4e..902ed8a 100644 --- a/lib/views/home/home_part.dart +++ b/lib/views/home/home_part.dart @@ -4,8 +4,10 @@ /// 最新变化: 2026-04-02 支持深色模式 import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../../constants/app_constants.dart'; +import '../../../services/get/theme_controller.dart'; import '../../../utils/http/poetry_api.dart'; import '../../../utils/audio_manager.dart'; import 'set/home_components.dart'; @@ -106,6 +108,8 @@ class _PoetryCardState extends State { @override Widget build(BuildContext context) { final isDark = widget.isDark; + final themeController = Get.find(); + final themeColor = themeController.currentThemeColor; final card = GestureDetector( onTap: () { AudioManager().playClickSound(); @@ -129,16 +133,16 @@ class _PoetryCardState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - _buildTimeBar(isDark), + _buildTimeBar(isDark, themeColor), Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - _buildTitleSection(isDark), + _buildTitleSection(isDark, themeColor), if (widget.poetryData.drtime.isNotEmpty) ...[ - _buildContentSection(context, isDark), + _buildContentSection(context, isDark, themeColor), const SizedBox(height: 3), ], Align( @@ -157,27 +161,27 @@ class _PoetryCardState extends State { style: TextStyle( fontSize: 12, fontWeight: FontWeight.w500, - color: AppConstants.primaryColor, + color: themeColor, ), ), const SizedBox(width: 4), Icon( Icons.format_quote, - color: AppConstants.primaryColor, + color: themeColor, size: 14, ), ], ), ), ), - _buildNameSection(isDark), + _buildNameSection(isDark, themeColor), const SizedBox(height: 12), if (widget.keywordList.isNotEmpty) ...[ - _buildKeywordSection(isDark), + _buildKeywordSection(isDark, themeColor), const SizedBox(height: 16), ], if (widget.poetryData.introduce.isNotEmpty) ...[ - _buildIntroductionSection(context, isDark), + _buildIntroductionSection(context, isDark, themeColor), ], ], ), @@ -185,7 +189,7 @@ class _PoetryCardState extends State { ], ), ), - _buildCopyTip(isDark), + _buildCopyTip(isDark, themeColor), ], ), ); @@ -196,7 +200,7 @@ class _PoetryCardState extends State { return card; } - Widget _buildTimeBar(bool isDark) { + Widget _buildTimeBar(bool isDark, Color themeColor) { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { @@ -209,10 +213,7 @@ class _PoetryCardState extends State { padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), decoration: BoxDecoration( gradient: LinearGradient( - colors: [ - AppConstants.primaryColor.withAlpha(204), - AppConstants.primaryColor, - ], + colors: [themeColor.withAlpha(204), themeColor], begin: Alignment.topLeft, end: Alignment.bottomRight, ), @@ -251,7 +252,7 @@ class _PoetryCardState extends State { ); } - Widget _buildCopyTip(bool isDark) { + Widget _buildCopyTip(bool isDark, Color themeColor) { if (!_globalTipsEnabled || !_showCopyTip) { return const SizedBox.shrink(); } @@ -264,11 +265,11 @@ class _PoetryCardState extends State { child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( - color: AppConstants.primaryColor, + color: themeColor, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( - color: AppConstants.primaryColor.withAlpha(76), + color: themeColor.withAlpha(76), blurRadius: 8, offset: const Offset(0, 2), ), @@ -296,7 +297,7 @@ class _PoetryCardState extends State { ); } - Widget _buildTitleSection(bool isDark) { + Widget _buildTitleSection(bool isDark, Color themeColor) { final isLoading = widget.sectionLoadingStates?['title'] ?? false; return SizedBox( @@ -321,7 +322,7 @@ class _PoetryCardState extends State { child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation( - AppConstants.primaryColor, + themeColor, ), ), ), @@ -357,7 +358,7 @@ class _PoetryCardState extends State { ); } - Widget _buildNameSection(bool isDark) { + Widget _buildNameSection(bool isDark, Color themeColor) { final isLoading = widget.sectionLoadingStates?['name'] ?? false; return Container( @@ -368,25 +369,20 @@ class _PoetryCardState extends State { gradient: LinearGradient( colors: isDark ? [const Color(0xFF2A2A2A), const Color(0xFF252525)] - : [ - AppConstants.primaryColor.withAlpha(26), - AppConstants.primaryColor.withAlpha(13), - ], + : [themeColor.withAlpha(26), themeColor.withAlpha(13)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(12), border: Border.all( - color: isDark - ? Colors.grey[700]! - : AppConstants.primaryColor.withAlpha(51), + color: isDark ? Colors.grey[700]! : themeColor.withAlpha(51), width: 1, ), boxShadow: [ BoxShadow( color: isDark ? Colors.black.withAlpha(40) - : AppConstants.primaryColor.withAlpha(26), + : themeColor.withAlpha(26), blurRadius: 8, offset: const Offset(0, 2), ), @@ -412,7 +408,7 @@ class _PoetryCardState extends State { child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation( - AppConstants.primaryColor, + themeColor, ), ), ), @@ -456,7 +452,7 @@ class _PoetryCardState extends State { return text; } - Widget _buildKeywordSection(bool isDark) { + Widget _buildKeywordSection(bool isDark, Color themeColor) { final isLoading = widget.sectionLoadingStates?['keywords'] ?? false; return Column( @@ -475,7 +471,7 @@ class _PoetryCardState extends State { child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation( - AppConstants.primaryColor, + themeColor, ), ), ), @@ -513,18 +509,14 @@ class _PoetryCardState extends State { ), decoration: BoxDecoration( color: isDark - ? AppConstants.secondaryColor.withAlpha( - 40, - ) - : AppConstants.secondaryColor.withAlpha( - 26, - ), + ? themeColor.withAlpha(40) + : themeColor.withAlpha(26), borderRadius: BorderRadius.circular(8), ), child: Text( keyword, style: TextStyle( - color: AppConstants.secondaryColor, + color: themeColor, fontSize: 12, ), overflow: TextOverflow.ellipsis, @@ -550,14 +542,14 @@ class _PoetryCardState extends State { ), decoration: BoxDecoration( color: isDark - ? AppConstants.primaryColor.withAlpha(40) - : AppConstants.primaryColor.withAlpha(26), + ? themeColor.withAlpha(40) + : themeColor.withAlpha(26), borderRadius: BorderRadius.circular(12), ), child: Text( widget.poetryData.alias, style: TextStyle( - color: AppConstants.primaryColor, + color: themeColor, fontSize: 12, fontWeight: FontWeight.w500, ), @@ -604,7 +596,11 @@ class _PoetryCardState extends State { ); } - Widget _buildContentSection(BuildContext context, bool isDark) { + Widget _buildContentSection( + BuildContext context, + bool isDark, + Color themeColor, + ) { final isLoading = widget.sectionLoadingStates?['content'] ?? false; return Builder( @@ -622,7 +618,7 @@ class _PoetryCardState extends State { decoration: BoxDecoration( color: isDark ? Colors.grey[800]!.withAlpha(80) - : AppConstants.primaryColor.withAlpha(20), + : themeColor.withAlpha(20), borderRadius: BorderRadius.circular(8), ), child: isLoading @@ -635,9 +631,7 @@ class _PoetryCardState extends State { height: 16, child: CircularProgressIndicator( strokeWidth: 2, - valueColor: AlwaysStoppedAnimation( - AppConstants.primaryColor, - ), + valueColor: AlwaysStoppedAnimation(themeColor), ), ), const SizedBox(width: 8), @@ -659,9 +653,7 @@ class _PoetryCardState extends State { style: TextStyle( fontSize: 13, fontWeight: FontWeight.w600, - color: isDark - ? Colors.grey[300] - : AppConstants.primaryColor, + color: isDark ? Colors.grey[300] : themeColor, ), ), const SizedBox(height: 8), @@ -680,7 +672,11 @@ class _PoetryCardState extends State { ); } - Widget _buildIntroductionSection(BuildContext context, bool isDark) { + Widget _buildIntroductionSection( + BuildContext context, + bool isDark, + Color themeColor, + ) { final isLoading = widget.sectionLoadingStates?['introduction'] ?? false; return Builder( @@ -710,9 +706,7 @@ class _PoetryCardState extends State { height: 20, child: CircularProgressIndicator( strokeWidth: 2, - valueColor: AlwaysStoppedAnimation( - AppConstants.primaryColor, - ), + valueColor: AlwaysStoppedAnimation(themeColor), ), ), const SizedBox(height: 8), diff --git a/lib/views/home/set/home_components.dart b/lib/views/home/set/home_components.dart index ff80553..b734002 100644 --- a/lib/views/home/set/home_components.dart +++ b/lib/views/home/set/home_components.dart @@ -12,6 +12,7 @@ import 'package:get/get.dart'; import 'package:path_provider/path_provider.dart'; import 'package:share_plus/share_plus.dart'; import '../../../constants/app_constants.dart'; +import '../../../services/get/theme_controller.dart'; import '../../../utils/http/poetry_api.dart'; import 'home-load.dart'; @@ -23,14 +24,14 @@ class LoadingWidget extends StatelessWidget { @override Widget build(BuildContext context) { + final themeController = Get.find(); + final themeColor = themeController.currentThemeColor; return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation( - AppConstants.primaryColor, - ), + valueColor: AlwaysStoppedAnimation(themeColor), ), const SizedBox(height: 16), Text( @@ -145,7 +146,7 @@ class CustomErrorWidget extends StatelessWidget { ElevatedButton( onPressed: onRetry, style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: Get.find().currentThemeColor, ), child: const Text('重试'), ), @@ -401,15 +402,17 @@ class FloatingShareButton extends StatelessWidget { @override Widget build(BuildContext context) { + final themeController = Get.find(); + final themeColor = themeController.currentThemeColor; return Container( width: 56, height: 56, decoration: BoxDecoration( - color: AppConstants.secondaryColor, + color: themeColor, shape: BoxShape.circle, boxShadow: [ BoxShadow( - color: AppConstants.secondaryColor.withAlpha(76), + color: themeColor.withAlpha(76), blurRadius: 8, offset: const Offset(0, 4), ), @@ -470,7 +473,9 @@ class FloatingPreviousButton extends StatelessWidget { child: Center( child: Icon( Icons.arrow_back, - color: isDark ? Colors.grey[300] : AppConstants.primaryColor, + color: isDark + ? Colors.grey[300] + : Get.find().currentThemeColor, size: 28, ), ), @@ -518,7 +523,9 @@ class FloatingNextButton extends StatelessWidget { child: Center( child: Icon( Icons.arrow_forward, - color: isDark ? Colors.grey[300] : AppConstants.primaryColor, + color: isDark + ? Colors.grey[300] + : Get.find().currentThemeColor, size: 28, ), ), @@ -581,7 +588,9 @@ class FloatingLikeButton extends StatelessWidget { child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation( - isDark ? Colors.grey[300]! : AppConstants.primaryColor, + isDark + ? Colors.grey[300]! + : Get.find().currentThemeColor, ), ), ) @@ -608,6 +617,8 @@ class StatsCard extends StatelessWidget { @override Widget build(BuildContext context) { + final themeController = Get.find(); + final themeColor = themeController.currentThemeColor; return Container( margin: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.all(16), @@ -631,7 +642,7 @@ class StatsCard extends StatelessWidget { style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, - color: AppConstants.primaryColor, + color: themeColor, ), ), const SizedBox(height: 12), diff --git a/lib/views/profile/app-info.dart b/lib/views/profile/app-info.dart index f41523a..5d22e92 100644 --- a/lib/views/profile/app-info.dart +++ b/lib/views/profile/app-info.dart @@ -8,6 +8,7 @@ import 'package:platform_info/platform_info.dart'; import 'package:flutter_udid/flutter_udid.dart'; import '../../../config/app_config.dart'; import '../../../constants/app_constants.dart'; +import '../../../models/colors/theme_colors.dart'; import '../../../controllers/shared_preferences_storage_controller.dart'; import '../../../services/get/theme_controller.dart'; @@ -102,6 +103,7 @@ class _AppInfoPageState extends State { Widget build(BuildContext context) { return Obx(() { final isDark = _themeController.isDarkMode; + final primaryColor = _themeController.currentThemeColor; return Scaffold( backgroundColor: isDark ? const Color(0xFF1A1A1A) @@ -109,16 +111,13 @@ class _AppInfoPageState extends State { appBar: AppBar( title: Text( '应用信息', - style: TextStyle( - color: AppConstants.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold), ), backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, elevation: 0, centerTitle: true, leading: IconButton( - icon: Icon(Icons.arrow_back, color: AppConstants.primaryColor), + icon: Icon(Icons.arrow_back, color: primaryColor), onPressed: () => Navigator.of(context).pop(), ), actions: [ @@ -139,15 +138,15 @@ class _AppInfoPageState extends State { body: ListView( padding: const EdgeInsets.all(16), children: [ - _buildHeaderCard(), + _buildHeaderCard(primaryColor), const SizedBox(height: 16), _buildTechStackCard(isDark), const SizedBox(height: 16), - _buildBuildInfoCard(context, isDark), + _buildBuildInfoCard(context, isDark, primaryColor), const SizedBox(height: 16), _buildServerInfoCard(isDark), const SizedBox(height: 16), - _buildDeviceInfoCard(context, isDark), + _buildDeviceInfoCard(context, isDark, primaryColor), const SizedBox(height: 16), _buildUpdateLogCard(isDark), const SizedBox(height: 16), @@ -160,7 +159,7 @@ class _AppInfoPageState extends State { }); } - Widget _buildHeaderCard() { + Widget _buildHeaderCard(Color primaryColor) { return ClipRRect( borderRadius: BorderRadius.circular(16), child: BackdropFilter( @@ -170,9 +169,9 @@ class _AppInfoPageState extends State { decoration: BoxDecoration( gradient: LinearGradient( colors: [ - AppConstants.primaryColor.withValues(alpha: 0.66), - AppConstants.primaryColor.withValues(alpha: 0.7), - AppConstants.primaryColor.withValues(alpha: 0.99), + primaryColor.withValues(alpha: 0.66), + primaryColor.withValues(alpha: 0.7), + primaryColor.withValues(alpha: 0.99), ], begin: Alignment.topLeft, end: Alignment.bottomRight, @@ -184,7 +183,7 @@ class _AppInfoPageState extends State { ), boxShadow: [ BoxShadow( - color: AppConstants.primaryColor.withValues(alpha: 0.35), + color: primaryColor.withValues(alpha: 0.35), blurRadius: 20, offset: const Offset(0, 4), ), @@ -386,7 +385,11 @@ class _AppInfoPageState extends State { ); } - Widget _buildBuildInfoCard(BuildContext context, bool isDark) { + Widget _buildBuildInfoCard( + BuildContext context, + bool isDark, + Color primaryColor, + ) { String buildSdk = 'Unknown'; try { final String osName = io.Platform.operatingSystem; @@ -435,10 +438,10 @@ class _AppInfoPageState extends State { Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: Colors.green.withValues(alpha: 0.1), + color: primaryColor.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(8), ), - child: Icon(Icons.build, color: Colors.green[700], size: 20), + child: Icon(Icons.build, color: primaryColor, size: 20), ), const SizedBox(width: 12), Text( @@ -474,25 +477,25 @@ class _AppInfoPageState extends State { isDark, ), _buildInfoItem('Build SDK', buildSdk, Icons.new_releases, isDark), - _buildLicenseItem(context, isDark), + _buildLicenseItem(context, isDark, primaryColor), ], ), ); } - Widget _buildLicenseItem(BuildContext context, bool isDark) { + Widget _buildLicenseItem( + BuildContext context, + bool isDark, + Color primaryColor, + ) { return InkWell( - onTap: () => _showFlutterLicense(context, isDark), + onTap: () => _showFlutterLicense(context, isDark, primaryColor), borderRadius: BorderRadius.circular(8), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Row( children: [ - Icon( - Icons.gavel, - size: 20, - color: isDark ? Colors.grey[400] : Colors.grey[600], - ), + Icon(Icons.gavel, size: 20, color: primaryColor), const SizedBox(width: 12), Expanded( child: Column( @@ -528,7 +531,11 @@ class _AppInfoPageState extends State { ); } - void _showFlutterLicense(BuildContext context, bool isDark) { + void _showFlutterLicense( + BuildContext context, + bool isDark, + Color primaryColor, + ) { final licenses = [ {'name': 'Flutter SDK', 'license': 'BSD 3-Clause'}, {'name': 'OpenHarmony SDK', 'license': 'Apache 2.0'}, @@ -545,7 +552,7 @@ class _AppInfoPageState extends State { backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, title: Row( children: [ - Icon(Icons.description, color: AppConstants.primaryColor), + Icon(Icons.description, color: primaryColor), const SizedBox(width: 8), Text( '开源框架', @@ -574,14 +581,10 @@ class _AppInfoPageState extends State { Container( padding: const EdgeInsets.all(6), decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: primaryColor.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(6), ), - child: Icon( - Icons.widgets, - size: 16, - color: AppConstants.primaryColor, - ), + child: Icon(Icons.widgets, size: 16, color: primaryColor), ), const SizedBox(width: 12), Expanded( @@ -618,10 +621,7 @@ class _AppInfoPageState extends State { actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), - child: Text( - '关闭', - style: TextStyle(color: AppConstants.primaryColor), - ), + child: Text('关闭', style: TextStyle(color: primaryColor)), ), ], ), @@ -678,7 +678,11 @@ class _AppInfoPageState extends State { ); } - Widget _buildDeviceInfoCard(BuildContext context, bool isDark) { + Widget _buildDeviceInfoCard( + BuildContext context, + bool isDark, + Color primaryColor, + ) { final platform = Platform.instance; bool isHarmonyOS = false; @@ -793,14 +797,10 @@ class _AppInfoPageState extends State { Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: Colors.purple.withValues(alpha: 0.1), + color: primaryColor.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(8), ), - child: Icon( - Icons.devices, - color: Colors.purple[700], - size: 20, - ), + child: Icon(Icons.devices, color: primaryColor, size: 20), ), const SizedBox(width: 12), Text( @@ -830,6 +830,7 @@ class _AppInfoPageState extends State { platformName, Icons.phone_iphone, isDark, + primaryColor, ), if (!isHarmonyOS) ...[ _buildGridInfoItem( @@ -837,17 +838,37 @@ class _AppInfoPageState extends State { designStyle, Icons.palette, isDark, + primaryColor, ), ], - _buildGridInfoItem('设备类型', deviceType, Icons.devices, isDark), - _buildGridInfoItem('构建模式', buildMode, Icons.build, isDark), - _buildGridInfoItem('运行环境', runtimeEnv, Icons.code, isDark), + _buildGridInfoItem( + '设备类型', + deviceType, + Icons.devices, + isDark, + primaryColor, + ), + _buildGridInfoItem( + '构建模式', + buildMode, + Icons.build, + isDark, + primaryColor, + ), + _buildGridInfoItem( + '运行环境', + runtimeEnv, + Icons.code, + isDark, + primaryColor, + ), _buildGridCopyableItem( context, 'Flutter UUID', _udid, Icons.perm_identity, isDark, + primaryColor, ), ], ), @@ -1181,6 +1202,7 @@ class _AppInfoPageState extends State { String value, IconData icon, bool isDark, + Color primaryColor, ) { return Container( padding: const EdgeInsets.all(12), @@ -1198,7 +1220,7 @@ class _AppInfoPageState extends State { children: [ Row( children: [ - Icon(icon, size: 18, color: AppConstants.primaryColor), + Icon(icon, size: 18, color: primaryColor), const SizedBox(width: 8), Expanded( child: Text( @@ -1236,6 +1258,7 @@ class _AppInfoPageState extends State { String value, IconData icon, bool isDark, + Color primaryColor, ) { return InkWell( onTap: () => _copyToClipboard(context, value), @@ -1257,11 +1280,7 @@ class _AppInfoPageState extends State { children: [ Row( children: [ - Icon( - icon, - size: 16, - color: isDark ? Colors.grey[400] : Colors.grey[600], - ), + Icon(icon, size: 16, color: primaryColor), const SizedBox(width: 6), Expanded( child: Text( @@ -1277,7 +1296,7 @@ class _AppInfoPageState extends State { Icon( Icons.content_copy, size: 14, - color: AppConstants.primaryColor.withValues(alpha: 0.6), + color: primaryColor.withValues(alpha: 0.6), ), ], ), @@ -1397,6 +1416,7 @@ class _AppInfoPageState extends State { void _copyToClipboard(BuildContext context, String text) { Clipboard.setData(ClipboardData(text: text)); + final primaryColor = _themeController.currentThemeColor; ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Row( @@ -1406,7 +1426,7 @@ class _AppInfoPageState extends State { Text('$text 已复制到剪贴板'), ], ), - backgroundColor: AppConstants.primaryColor, + backgroundColor: primaryColor, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), duration: const Duration(seconds: 2), diff --git a/lib/views/profile/components/bug_list_page.dart b/lib/views/profile/components/bug_list_page.dart index 428465e..daa2f3f 100644 --- a/lib/views/profile/components/bug_list_page.dart +++ b/lib/views/profile/components/bug_list_page.dart @@ -1,13 +1,13 @@ /// 时间: 2026-03-30 /// 功能: 已知bug列表页面 /// 介绍: 显示应用已知bug、解决方法和解决时间的底部弹窗页面 -/// 最新变化: 新增bug列表页面,支持下拉刷新和滚动查看 +/// 最新变化: 新增bug列表页面,支持下拉刷新和滚动查看, 支持动态主题色 import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; -import '../../../constants/app_constants.dart'; +import '../../../models/colors/app_colors.dart'; import '../../../services/get/theme_controller.dart'; class BugListPage extends StatefulWidget { @@ -70,7 +70,7 @@ class _BugListPageState extends State { 'description': '暂未适配横屏', 'severity': 'high', 'status': 'pending', - 'solution': '增加重试机制和离线缓存功能', + 'solution': '预计下个月适配横屏', 'reproduction': '1. 开启屏幕旋转,手机横屏', 'resolveTime': '适配中', 'reportTime': '2026-03-22', @@ -108,7 +108,7 @@ class _BugListPageState extends State { }, { 'id': 7, - 'title': '主页点击“上一条” 显示无上一条', + 'title': '主页点击"上一条" 显示无上一条', 'description': '未读取到历史记录', 'severity': 'high', 'status': 'in_progress', @@ -149,6 +149,20 @@ class _BugListPageState extends State { 'expanded': false, // 解决方案展开状态 'reproductionExpanded': false, // 复现步骤展开状态 }, + { + 'id': 12, + 'title': '显示错误的分享', + 'description': '点击分享后,取消分享,依旧显示分享成功', + 'severity': 'low', + 'status': 'pending', + 'solution': '全部触发', + 'reproduction': '主页 点击分享 取消分享 显示分享成功', + 'resolveTime': '暂无修复计划', + 'reportTime': '2026-03-18', + 'affectedUsers': '多数用户', + 'expanded': false, // 解决方案展开状态 + 'reproductionExpanded': false, // 复现步骤展开状态 + }, { 'id': 10, @@ -156,7 +170,7 @@ class _BugListPageState extends State { 'description': '未读取到历史记录', 'severity': 'low', 'status': '', - 'solution': '用户短时间内多次刷新获取api数据,导致服务器启动防止cc自我保护机制,不会此ip下放数据', + 'solution': '用户短时间内多次刷新获取api数据,导致服务器启动防止cc自我保护机制,不会对此ip下放数据', 'reproduction': '天气频繁切换,导致温度显示异常999', 'resolveTime': '下个版本', 'reportTime': '2026-03', @@ -214,24 +228,22 @@ class _BugListPageState extends State { Color _getSeverityColor(String severity) { switch (severity) { case 'high': - return Colors.red; + return AppColors.iosRed; case 'medium': - return Colors.orange; + return AppColors.iosOrange; case 'low': - return Colors.green; + return AppColors.iosGreen; default: - return Colors.grey; + return AppColors.iosGray; } } String _getSeverityText(String severity) { switch (severity) { case 'high': - // 高优先级默认红色 return '高'; case 'medium': return '中'; - case 'low': return '低'; default: @@ -242,17 +254,13 @@ class _BugListPageState extends State { Color _getStatusColor(String status) { switch (status) { case 'resolved': - // 已解决状态默认绿色 - return Colors.green; + return AppColors.iosGreen; case 'in_progress': - // 解决中状态默认蓝色 - return Colors.blue; + return AppColors.iosBlue; case 'pending': - // 待解决状态默认橙色 - return Colors.orange; + return AppColors.iosOrange; default: - return Colors.grey; - // 未知状态默认灰色 + return AppColors.iosGray; } } @@ -270,9 +278,7 @@ class _BugListPageState extends State { } Future _refresh() async { - // 模拟网络请求延迟 await Future.delayed(const Duration(seconds: 1)); - HapticFeedback.lightImpact(); } @@ -282,18 +288,16 @@ class _BugListPageState extends State { final isDark = _themeController.isDarkMode; return Container( decoration: BoxDecoration( - color: isDark ? const Color(0xFF1A1A1A) : Colors.white, + color: AppColors.background, borderRadius: const BorderRadius.vertical(top: Radius.circular(20)), ), child: Column( children: [ - // 顶部拖拽条和标题 _buildHeader(isDark), - // bug列表 Expanded( child: RefreshIndicator( onRefresh: _refresh, - color: AppConstants.primaryColor, + color: AppColors.primary, child: ListView.builder( controller: _scrollController, physics: const AlwaysScrollableScrollPhysics(), @@ -318,24 +322,22 @@ class _BugListPageState extends State { Widget _buildHeader(bool isDark) { return Column( children: [ - // 拖拽条 Container( width: 40, height: 4, margin: const EdgeInsets.only(top: 8), decoration: BoxDecoration( - color: isDark ? Colors.grey[600] : Colors.grey[300], + color: AppColors.divider, borderRadius: BorderRadius.circular(2), ), ), - // 标题栏 Container( padding: const EdgeInsets.all(16), child: Row( children: [ Icon( Icons.bug_report, - color: AppConstants.primaryColor, + color: AppColors.primary, size: 24, ), const SizedBox(width: 12), @@ -345,7 +347,7 @@ class _BugListPageState extends State { style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, - color: AppConstants.primaryColor, + color: AppColors.primary, ), ), ), @@ -353,13 +355,13 @@ class _BugListPageState extends State { onPressed: () => Navigator.pop(context), child: Text( '关闭', - style: TextStyle(color: isDark ? Colors.white : null), + style: TextStyle(color: AppColors.primaryText), ), ), ], ), ), - Divider(height: 1, color: isDark ? Colors.grey[700] : null), + Divider(height: 1, color: AppColors.divider), ], ); } @@ -375,7 +377,7 @@ class _BugListPageState extends State { Container( width: 40, height: 1, - color: isDark ? Colors.grey[600] : Colors.grey[300], + color: AppColors.divider, ), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), @@ -383,14 +385,14 @@ class _BugListPageState extends State { '已经到底了', style: TextStyle( fontSize: 13, - color: isDark ? Colors.grey[400] : Colors.grey[500], + color: AppColors.tertiaryText, ), ), ), Container( width: 40, height: 1, - color: isDark ? Colors.grey[600] : Colors.grey[300], + color: AppColors.divider, ), ], ), @@ -399,7 +401,7 @@ class _BugListPageState extends State { '共 ${_bugs.length} 个已知问题', style: TextStyle( fontSize: 12, - color: isDark ? Colors.grey[500] : Colors.grey[400], + color: AppColors.tertiaryText, ), ), ], @@ -413,10 +415,10 @@ class _BugListPageState extends State { return Container( margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( - color: isDark ? const Color(0xFF2A2A2A) : Colors.white, + color: AppColors.surface, borderRadius: BorderRadius.circular(12), border: Border.all( - color: isDark ? Colors.grey[700]! : Colors.grey[200]!, + color: AppColors.divider, ), boxShadow: [ BoxShadow( @@ -429,13 +431,11 @@ class _BugListPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // 顶部信息行 Container( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - // 标题和状态标签 Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -445,7 +445,7 @@ class _BugListPageState extends State { style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, - color: isDark ? Colors.white : Colors.black87, + color: AppColors.primaryText, ), ), ), @@ -477,17 +477,15 @@ class _BugListPageState extends State { ], ), const SizedBox(height: 8), - // 问题描述 Text( bug['description'] ?? '暂无描述', style: TextStyle( fontSize: 14, - color: isDark ? Colors.grey[400] : Colors.black54, + color: AppColors.secondaryText, height: 1.4, ), ), const SizedBox(height: 12), - // 严重程度和影响用户 Row( children: [ Container( @@ -525,20 +523,19 @@ class _BugListPageState extends State { Icon( Icons.people, size: 14, - color: isDark ? Colors.grey[400] : Colors.grey[600], + color: AppColors.secondaryText, ), const SizedBox(width: 4), Text( bug['affectedUsers'] ?? '未知用户', style: TextStyle( fontSize: 12, - color: isDark ? Colors.grey[400] : Colors.grey[600], + color: AppColors.secondaryText, ), ), ], ), const SizedBox(height: 12), - // 解决方案和复现步骤按钮 Row( children: [ Expanded( @@ -553,18 +550,14 @@ class _BugListPageState extends State { style: const TextStyle(fontSize: 14), ), style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor.withValues( - alpha: 0.1, - ), - foregroundColor: AppConstants.primaryColor, + backgroundColor: AppColors.primaryWithAlpha(25), + foregroundColor: AppColors.primary, elevation: 0, padding: const EdgeInsets.symmetric(vertical: 8), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide( - color: AppConstants.primaryColor.withValues( - alpha: 0.3, - ), + color: AppColors.primaryWithAlpha(76), ), ), ), @@ -585,17 +578,14 @@ class _BugListPageState extends State { style: const TextStyle(fontSize: 14), ), style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.secondaryColor - .withValues(alpha: 0.1), - foregroundColor: const Color(0xFF018786), // 更深的青色 + backgroundColor: AppColors.accentWithAlpha(25), + foregroundColor: AppColors.accent, elevation: 0, padding: const EdgeInsets.symmetric(vertical: 8), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide( - color: const Color( - 0xFF018786, - ).withValues(alpha: 0.3), + color: AppColors.accentWithAlpha(76), ), ), ), @@ -606,13 +596,12 @@ class _BugListPageState extends State { ], ), ), - // 解决方案区域(可展开/收起) if (isExpanded) ...[ - Divider(height: 1, color: isDark ? Colors.grey[700] : null), + Divider(height: 1, color: AppColors.divider), Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: isDark ? const Color(0xFF333333) : Colors.grey[50], + color: AppColors.card, borderRadius: const BorderRadius.only( bottomLeft: Radius.circular(12), bottomRight: Radius.circular(12), @@ -625,7 +614,7 @@ class _BugListPageState extends State { children: [ Icon( Icons.lightbulb_outline, - color: AppConstants.primaryColor, + color: AppColors.primary, size: 16, ), const SizedBox(width: 8), @@ -634,7 +623,7 @@ class _BugListPageState extends State { style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, - color: AppConstants.primaryColor, + color: AppColors.primary, ), ), ], @@ -644,39 +633,38 @@ class _BugListPageState extends State { bug['solution'] ?? '暂无解决方案', style: TextStyle( fontSize: 13, - color: isDark ? Colors.grey[400] : Colors.black54, + color: AppColors.secondaryText, height: 1.4, ), ), const SizedBox(height: 12), - // 时间信息 Row( children: [ Icon( Icons.schedule, size: 14, - color: isDark ? Colors.grey[400] : Colors.grey[600], + color: AppColors.secondaryText, ), const SizedBox(width: 4), Text( '预计解决: ${bug['resolveTime'] ?? '待定'}', style: TextStyle( fontSize: 12, - color: isDark ? Colors.grey[400] : Colors.grey[600], + color: AppColors.secondaryText, ), ), const SizedBox(width: 16), Icon( Icons.report, size: 14, - color: isDark ? Colors.grey[400] : Colors.grey[600], + color: AppColors.secondaryText, ), const SizedBox(width: 4), Text( '报告时间: ${bug['reportTime'] ?? '未知'}', style: TextStyle( fontSize: 12, - color: isDark ? Colors.grey[400] : Colors.grey[600], + color: AppColors.secondaryText, ), ), ], @@ -685,13 +673,12 @@ class _BugListPageState extends State { ), ), ], - // 复现步骤区域(可展开/收起) if (bug['reproductionExpanded']) ...[ - Divider(height: 1, color: isDark ? Colors.grey[700] : null), + Divider(height: 1, color: AppColors.divider), Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: isDark ? const Color(0xFF333333) : Colors.grey[50], + color: AppColors.card, borderRadius: const BorderRadius.only( bottomLeft: Radius.circular(12), bottomRight: Radius.circular(12), @@ -704,7 +691,7 @@ class _BugListPageState extends State { children: [ Icon( Icons.replay, - color: const Color(0xFF018786), // 更深的青色 + color: AppColors.accent, size: 16, ), const SizedBox(width: 8), @@ -713,7 +700,7 @@ class _BugListPageState extends State { style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, - color: const Color(0xFF018786), // 更深的青色 + color: AppColors.accent, ), ), ], @@ -723,7 +710,7 @@ class _BugListPageState extends State { bug['reproduction'] ?? '暂无复现步骤', style: TextStyle( fontSize: 13, - color: isDark ? Colors.grey[400] : Colors.black54, + color: AppColors.secondaryText, height: 1.4, ), ), @@ -742,9 +729,9 @@ void showBugListBottomSheet(BuildContext context) { showModalBottomSheet( context: context, backgroundColor: Colors.transparent, - isScrollControlled: true, // 允许弹窗占据全屏高度 + isScrollControlled: true, builder: (context) => Container( - height: MediaQuery.of(context).size.height * 0.85, // 设置弹窗高度为屏幕的85% + height: MediaQuery.of(context).size.height * 0.85, child: const BugListPage(), ), ); diff --git a/lib/views/profile/components/entire_page.dart b/lib/views/profile/components/entire_page.dart index 34e397a..646a87a 100644 --- a/lib/views/profile/components/entire_page.dart +++ b/lib/views/profile/components/entire_page.dart @@ -1,13 +1,14 @@ /// 时间: 2026-04-01 /// 功能: 全站统计页面 /// 介绍: 展示网站统计数据,包括收录数量、热度统计、热门内容等 -/// 最新变化: 新建页面,iOS风格设计 +/// 最新变化: 支持动态主题色设置 + library; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; -import '../../../constants/app_constants.dart'; +import '../../../models/colors/app_colors.dart'; import '../../../utils/http/http_client.dart'; import '../../../services/network_listener_service.dart'; import '../../../services/get/theme_controller.dart'; @@ -88,12 +89,16 @@ class _EntirePageState extends State context: context, barrierDismissible: false, builder: (BuildContext context) { - return const AlertDialog( + return AlertDialog( + backgroundColor: AppColors.surface, content: Row( children: [ - CircularProgressIndicator(), - SizedBox(width: 16), - Text('正在检测网络状态...'), + CircularProgressIndicator(color: AppColors.primary), + const SizedBox(width: 16), + Text( + '正在检测网络状态...', + style: TextStyle(color: AppColors.primaryText), + ), ], ), ); @@ -132,9 +137,7 @@ class _EntirePageState extends State return AnnotatedRegion( value: isDark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark, child: Scaffold( - backgroundColor: isDark - ? const Color(0xFF1A1A1A) - : const Color(0xFFF2F2F7), + backgroundColor: AppColors.background, appBar: _buildAppBar(isDark), body: _buildBody(isDark), ), @@ -144,19 +147,19 @@ class _EntirePageState extends State PreferredSizeWidget _buildAppBar(bool isDark) { return AppBar( - backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, + backgroundColor: AppColors.surface, elevation: 0, leading: IconButton( icon: Icon( Icons.arrow_back_ios, - color: isDark ? Colors.white : AppConstants.primaryColor, + color: AppColors.primary, ), onPressed: () => Navigator.pop(context), ), title: Text( '全站统计', style: TextStyle( - color: isDark ? Colors.white : Colors.black, + color: AppColors.primaryText, fontSize: 17, fontWeight: FontWeight.w600, ), @@ -166,7 +169,7 @@ class _EntirePageState extends State IconButton( icon: Icon( Icons.info_outline, - color: isDark ? Colors.white : AppConstants.primaryColor, + color: AppColors.primary, ), onPressed: _showServerInfo, tooltip: '服务器信息', @@ -176,7 +179,7 @@ class _EntirePageState extends State preferredSize: const Size.fromHeight(0.5), child: Container( height: 0.5, - color: isDark ? Colors.grey[700] : const Color(0xFFE5E5EA), + color: AppColors.divider, ), ), ); @@ -204,7 +207,7 @@ class _EntirePageState extends State width: width, height: height, decoration: BoxDecoration( - color: isDark ? Colors.grey[700] : const Color(0xFFE5E5EA), + color: isDark ? Colors.grey[700] : AppColors.iosLightGray, borderRadius: BorderRadius.circular(radius), ), ); @@ -235,7 +238,7 @@ class _EntirePageState extends State return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( - color: isDark ? Colors.grey[700] : const Color(0xFFE5E5EA), + color: isDark ? Colors.grey[700] : AppColors.iosLightGray, borderRadius: BorderRadius.circular(12), ), child: Column( @@ -273,7 +276,7 @@ class _EntirePageState extends State return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: isDark ? const Color(0xFF2A2A2A) : Colors.white, + color: AppColors.surface, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( @@ -320,7 +323,7 @@ class _EntirePageState extends State return Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( - color: isDark ? const Color(0xFF333333) : const Color(0xFFF2F2F7), + color: isDark ? AppColors.darkCard : AppColors.iosLightGray, borderRadius: BorderRadius.circular(12), ), child: Column( @@ -362,7 +365,7 @@ class _EntirePageState extends State return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: isDark ? const Color(0xFF2A2A2A) : Colors.white, + color: AppColors.surface, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( @@ -402,12 +405,12 @@ class _EntirePageState extends State width: 64, height: 64, decoration: BoxDecoration( - color: const Color(0xFFFF3B30).withValues(alpha: 0.1), + color: AppColors.error.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(32), ), - child: const Icon( + child: Icon( Icons.error_outline, - color: Color(0xFFFF3B30), + color: AppColors.error, size: 32, ), ), @@ -415,7 +418,7 @@ class _EntirePageState extends State Text( _errorMessage ?? '加载失败', style: TextStyle( - color: isDark ? Colors.grey[400] : const Color(0xFF8E8E93), + color: AppColors.tertiaryText, fontSize: 14, ), textAlign: TextAlign.center, @@ -424,7 +427,7 @@ class _EntirePageState extends State ElevatedButton( onPressed: _loadStatsData, style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: AppColors.primary, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 32, @@ -446,7 +449,7 @@ class _EntirePageState extends State return FadeTransition( opacity: _fadeAnimation, child: RefreshIndicator( - color: AppConstants.primaryColor, + color: AppColors.primary, onRefresh: _loadStatsData, child: ListView( padding: const EdgeInsets.all(16), @@ -473,8 +476,8 @@ class _EntirePageState extends State decoration: BoxDecoration( gradient: LinearGradient( colors: [ - AppConstants.primaryColor, - AppConstants.primaryColor.withValues(alpha: 0.8), + AppColors.primary, + AppColors.primary.withValues(alpha: 0.8), ], begin: Alignment.topLeft, end: Alignment.bottomRight, @@ -482,7 +485,7 @@ class _EntirePageState extends State borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( - color: AppConstants.primaryColor.withValues(alpha: 0.3), + color: AppColors.primary.withValues(alpha: 0.3), blurRadius: 12, offset: const Offset(0, 4), ), @@ -591,56 +594,56 @@ class _EntirePageState extends State 'label': '项目', 'value': _statsData?['count_category'] ?? 0, 'icon': Icons.category, - 'color': const Color(0xFF007AFF), + 'color': AppColors.iosBlue, 'showIcon': true, }, { 'label': '收录诗句', 'value': _statsData?['count_site'] ?? 0, 'icon': Icons.article, - 'color': const Color(0xFF34C759), + 'color': AppColors.iosGreen, 'showIcon': false, }, { 'label': '审核中', 'value': _statsData?['count_apply'] ?? 0, 'icon': Icons.pending, - 'color': const Color(0xFFFF9500), + 'color': AppColors.iosOrange, 'showIcon': true, }, { 'label': '已拒审', 'value': _statsData?['count_apply_reject'] ?? 0, 'icon': Icons.block, - 'color': const Color(0xFFFF3B30), + 'color': AppColors.iosRed, 'showIcon': true, }, { 'label': '每日一句', 'value': _statsData?['count_article'] ?? 0, 'icon': Icons.wb_sunny, - 'color': const Color(0xFF5856D6), + 'color': AppColors.iosPurple, 'showIcon': true, }, { 'label': '文章分类', 'value': _statsData?['count_article_category'] ?? 0, 'icon': Icons.folder, - 'color': const Color(0xFFAF52DE), + 'color': AppColors.iosPink, 'showIcon': true, }, { 'label': '推送', 'value': _statsData?['count_notice'] ?? 0, 'icon': Icons.campaign, - 'color': const Color(0xFF32ADE6), + 'color': AppColors.iosTeal, 'showIcon': true, }, { 'label': '开发者', 'value': _statsData?['count_link'] ?? 0, 'icon': Icons.people, - 'color': const Color(0xFFFF2D55), + 'color': AppColors.iosRed, 'showIcon': true, }, { @@ -687,7 +690,7 @@ class _EntirePageState extends State return Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( - color: isDark ? const Color(0xFF2A2A2A) : Colors.white, + color: AppColors.surface, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( @@ -699,7 +702,6 @@ class _EntirePageState extends State ), child: Column( children: [ - // 上行:icon和数据,比例2:1(有icon时1:1,无icon时数据占满) Expanded( flex: 2, child: Row( @@ -723,7 +725,7 @@ class _EntirePageState extends State style: TextStyle( fontSize: 22, fontWeight: FontWeight.bold, - color: isDark ? Colors.white : Colors.black, + color: AppColors.primaryText, ), textAlign: TextAlign.center, ), @@ -732,7 +734,6 @@ class _EntirePageState extends State ), ), const SizedBox(height: 4), - // 下行:描述 Expanded( flex: 1, child: Center( @@ -740,7 +741,7 @@ class _EntirePageState extends State label, style: TextStyle( fontSize: 12, - color: isDark ? Colors.grey[400] : const Color(0xFF3C3C43), + color: AppColors.secondaryText, ), maxLines: 1, overflow: TextOverflow.ellipsis, @@ -759,7 +760,7 @@ class _EntirePageState extends State '累计热度', _statsData?['cumulative_hits']?.toString() ?? '0', Icons.local_fire_department, - const Color(0xFFFF9500), + AppColors.iosOrange, isDark, ), const SizedBox(height: 12), @@ -767,7 +768,7 @@ class _EntirePageState extends State '累计点赞', _statsData?['cumulative_likes']?.toString() ?? '0', Icons.favorite, - const Color(0xFFFF2D55), + AppColors.iosRed, isDark, ), ], isDark); @@ -783,7 +784,7 @@ class _EntirePageState extends State return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: isDark ? const Color(0xFF2A2A2A) : Colors.white, + color: AppColors.surface, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( @@ -813,7 +814,7 @@ class _EntirePageState extends State label, style: TextStyle( fontSize: 14, - color: isDark ? Colors.grey[400] : const Color(0xFF8E8E93), + color: AppColors.secondaryText, ), ), const SizedBox(height: 4), @@ -822,7 +823,7 @@ class _EntirePageState extends State style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, - color: isDark ? Colors.white : Colors.black, + color: AppColors.primaryText, ), ), ], @@ -839,7 +840,7 @@ class _EntirePageState extends State '今日热门', _statsData?['top_hits_day'], Icons.today, - const Color(0xFFFF9500), + AppColors.iosOrange, isDark, ), const SizedBox(height: 12), @@ -847,7 +848,7 @@ class _EntirePageState extends State '本月热门', _statsData?['top_hits_month'], Icons.calendar_month, - const Color(0xFF007AFF), + AppColors.iosBlue, isDark, ), const SizedBox(height: 12), @@ -855,7 +856,7 @@ class _EntirePageState extends State '历史最热', _statsData?['top_hits_total'], Icons.history, - const Color(0xFF5856D6), + AppColors.iosPurple, isDark, ), const SizedBox(height: 12), @@ -863,7 +864,7 @@ class _EntirePageState extends State '最高点赞', _statsData?['top_like'], Icons.thumb_up, - const Color(0xFF34C759), + AppColors.iosGreen, isDark, ), ], isDark); @@ -882,7 +883,7 @@ class _EntirePageState extends State return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: isDark ? const Color(0xFF2A2A2A) : Colors.white, + color: AppColors.surface, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( @@ -914,7 +915,7 @@ class _EntirePageState extends State style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, - color: isDark ? Colors.white : Colors.black, + color: AppColors.primaryText, ), ), const SizedBox(height: 8), @@ -923,8 +924,8 @@ class _EntirePageState extends State style: TextStyle( fontSize: 13, color: hasData - ? (isDark ? Colors.grey[400] : const Color(0xFF3C3C43)) - : (isDark ? Colors.grey[500] : const Color(0xFF8E8E93)), + ? AppColors.secondaryText + : AppColors.tertiaryText, height: 1.5, ), maxLines: 3, @@ -954,7 +955,7 @@ class _EntirePageState extends State return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: isDark ? const Color(0xFF2A2A2A) : Colors.white, + color: AppColors.surface, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( @@ -970,12 +971,12 @@ class _EntirePageState extends State width: 40, height: 40, decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: AppColors.primary.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(10), ), - child: const Icon( + child: Icon( Icons.cake, - color: AppConstants.primaryColor, + color: AppColors.primary, size: 20, ), ), @@ -989,7 +990,7 @@ class _EntirePageState extends State style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, - color: isDark ? Colors.white : Colors.black, + color: AppColors.primaryText, ), ), const SizedBox(height: 4), @@ -999,9 +1000,7 @@ class _EntirePageState extends State buildTime, style: TextStyle( fontSize: 16, - color: isDark - ? Colors.grey[400] - : const Color(0xFF3C3C43), + color: AppColors.secondaryText, ), ), const SizedBox(width: 8), @@ -1011,14 +1010,14 @@ class _EntirePageState extends State vertical: 2, ), decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: AppColors.primary.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(10), ), child: Text( '已运行 $days 天', - style: const TextStyle( + style: TextStyle( fontSize: 12, - color: AppConstants.primaryColor, + color: AppColors.primary, fontWeight: FontWeight.w500, ), ), @@ -1041,7 +1040,7 @@ class _EntirePageState extends State ) { return Container( decoration: BoxDecoration( - color: isDark ? const Color(0xFF2A2A2A) : Colors.white, + color: AppColors.surface, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( @@ -1058,14 +1057,14 @@ class _EntirePageState extends State padding: const EdgeInsets.all(16), child: Row( children: [ - Icon(icon, color: AppConstants.primaryColor, size: 20), + Icon(icon, color: AppColors.primary, size: 20), const SizedBox(width: 8), Text( title, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, - color: isDark ? Colors.white : Colors.black, + color: AppColors.primaryText, ), ), ], diff --git a/lib/views/profile/components/login_register_dialog.dart b/lib/views/profile/components/login_register_dialog.dart index ef65b44..c7aa648 100644 --- a/lib/views/profile/components/login_register_dialog.dart +++ b/lib/views/profile/components/login_register_dialog.dart @@ -1,9 +1,12 @@ /// 时间: 2026-03-29 /// 功能: 填写投票凭证弹窗组件 /// 介绍: 提供投票功能的用户凭证填写功能 +/// 最新变化: 支持动态主题色设置 import 'package:flutter/material.dart'; -import '../../../constants/app_constants.dart'; +import 'package:get/get.dart'; +import '../../../models/colors/app_colors.dart'; +import '../../../services/get/theme_controller.dart'; import '../../../utils/http/vote_api.dart'; class LoginRegisterDialog extends StatefulWidget { @@ -16,6 +19,7 @@ class LoginRegisterDialog extends StatefulWidget { } class _LoginRegisterDialogState extends State { + final ThemeController _themeController = Get.find(); final _formKey = GlobalKey(); final _usernameController = TextEditingController(); bool _isLoading = false; @@ -63,9 +67,9 @@ class _LoginRegisterDialogState extends State { Navigator.pop(context); widget.onLoginSuccess?.call(); ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('验证成功'), - backgroundColor: AppConstants.successColor, + SnackBar( + content: const Text('验证成功'), + backgroundColor: AppColors.success, ), ); } @@ -80,9 +84,9 @@ class _LoginRegisterDialogState extends State { Navigator.pop(context); widget.onLoginSuccess?.call(); ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('注册并验证成功'), - backgroundColor: AppConstants.successColor, + SnackBar( + content: const Text('注册并验证成功'), + backgroundColor: AppColors.success, ), ); } @@ -92,7 +96,7 @@ class _LoginRegisterDialogState extends State { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(e.toString().replaceAll('Exception: ', '')), - backgroundColor: AppConstants.errorColor, + backgroundColor: AppColors.error, ), ); } @@ -107,80 +111,101 @@ class _LoginRegisterDialogState extends State { @override Widget build(BuildContext context) { - return Dialog( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), - child: Container( - padding: const EdgeInsets.all(20), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Text( - '填写 投票凭证', - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - ), - IconButton( - icon: const Icon(Icons.close), - onPressed: () => Navigator.pop(context), - ), - ], - ), - // const SizedBox(height: 8), - // 副标题 - const Text( - '微信号或手机号或邮箱作为投票凭证,\n任何人都可以填写,限时开放投票,\n投票凭证仅用于投票,不会泄露隐私.\n结束后删除会所有凭证,仅保留投票结果', - style: TextStyle(fontSize: 14, color: Colors.grey), - textAlign: TextAlign.center, - ), - const SizedBox(height: 2), - Form( - key: _formKey, - child: Column( + return Obx(() { + final isDark = _themeController.isDarkMode; + return Dialog( + backgroundColor: AppColors.surface, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + child: Container( + padding: const EdgeInsets.all(20), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - TextFormField( - controller: _usernameController, - decoration: const InputDecoration( - labelText: '点击填写', - hintText: '手机号/邮箱/微信号', - border: OutlineInputBorder(), - prefixIcon: Icon(Icons.person), + Text( + '填写 投票凭证', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: AppColors.primaryText, ), - validator: _validateUsername, ), - const SizedBox(height: 24), - SizedBox( - width: double.infinity, - child: ElevatedButton( - onPressed: _isLoading ? null : _submit, - style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, - padding: const EdgeInsets.symmetric(vertical: 14), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - child: _isLoading - ? const SizedBox( - width: 20, - height: 20, - child: CircularProgressIndicator( - strokeWidth: 2, - valueColor: AlwaysStoppedAnimation( - Colors.white, - ), - ), - ) - : const Text('验证', style: TextStyle(fontSize: 16)), - ), + IconButton( + icon: Icon(Icons.close, color: AppColors.tertiaryText), + onPressed: () => Navigator.pop(context), ), ], ), - ), - ], + Text( + '微信号或手机号或邮箱作为投票凭证,\n任何人都可以填写,限时开放投票,\n投票凭证仅用于投票,不会泄露隐私.\n结束后删除会所有凭证,仅保留投票结果', + style: TextStyle( + fontSize: 14, + color: AppColors.secondaryText, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 2), + Form( + key: _formKey, + child: Column( + children: [ + TextFormField( + controller: _usernameController, + style: TextStyle(color: AppColors.primaryText), + decoration: InputDecoration( + labelText: '点击填写', + hintText: '手机号/邮箱/微信号', + labelStyle: TextStyle(color: AppColors.secondaryText), + hintStyle: TextStyle(color: AppColors.tertiaryText), + border: OutlineInputBorder( + borderSide: BorderSide(color: AppColors.divider), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: AppColors.divider), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: AppColors.primary), + ), + prefixIcon: Icon(Icons.person, color: AppColors.primary), + ), + validator: _validateUsername, + ), + const SizedBox(height: 24), + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: _isLoading ? null : _submit, + style: ElevatedButton.styleFrom( + backgroundColor: AppColors.primary, + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric(vertical: 14), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + child: _isLoading + ? const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + valueColor: AlwaysStoppedAnimation( + Colors.white, + ), + ), + ) + : const Text('验证', style: TextStyle(fontSize: 16)), + ), + ), + ], + ), + ), + ], + ), ), - ), - ); + ); + }); } } diff --git a/lib/views/profile/components/pop-menu.dart b/lib/views/profile/components/pop-menu.dart index e0d0cc4..b81738c 100644 --- a/lib/views/profile/components/pop-menu.dart +++ b/lib/views/profile/components/pop-menu.dart @@ -3,7 +3,7 @@ import 'package:flutter/services.dart'; import 'package:flutter/foundation.dart' show kIsWeb; import 'package:share_plus/share_plus.dart'; import 'package:get/get.dart'; -import '../../../constants/app_constants.dart'; +import '../../../models/colors/app_colors.dart'; import '../../../services/isweb/wakelock_service.dart'; import '../../../services/get/theme_controller.dart'; import '../guide/beginner_page.dart'; @@ -91,12 +91,13 @@ class PopMenu extends StatelessWidget { showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('提示'), - content: Text(errorMessage), + backgroundColor: AppColors.surface, + title: Text('提示', style: TextStyle(color: AppColors.primaryText)), + content: Text(errorMessage, style: TextStyle(color: AppColors.secondaryText)), actions: [ TextButton( onPressed: () => Navigator.pop(context), - child: const Text('确定'), + child: Text('确定', style: TextStyle(color: AppColors.primary)), ), ], ), @@ -134,7 +135,7 @@ class PopMenu extends StatelessWidget { return Container( width: double.infinity, decoration: BoxDecoration( - color: isDark ? const Color(0xFF2A2A2A) : Colors.white, + color: AppColors.surface, borderRadius: const BorderRadius.vertical(top: Radius.circular(20)), boxShadow: [ BoxShadow( @@ -162,7 +163,7 @@ class PopMenu extends StatelessWidget { height: 4, margin: const EdgeInsets.only(top: 8), decoration: BoxDecoration( - color: isDark ? Colors.grey[600]! : Colors.grey[300]!, + color: AppColors.divider, borderRadius: BorderRadius.circular(2), ), ), @@ -208,16 +209,14 @@ class PopMenu extends StatelessWidget { IconData icon, VoidCallback? onTap, ) { - final isDark = _themeController.isDarkMode; - return ListTile( leading: Icon( icon, - color: isDark ? Colors.white70 : AppConstants.primaryColor, + color: AppColors.primary, ), title: Text( title, - style: TextStyle(color: isDark ? Colors.white70 : Colors.black87), + style: TextStyle(color: AppColors.primaryText), ), onTap: () { Navigator.pop(context); diff --git a/lib/views/profile/components/server_info_dialog.dart b/lib/views/profile/components/server_info_dialog.dart index 6d59199..fe48d5f 100644 --- a/lib/views/profile/components/server_info_dialog.dart +++ b/lib/views/profile/components/server_info_dialog.dart @@ -1,7 +1,9 @@ library; import 'package:flutter/material.dart'; -import '../../../constants/app_constants.dart'; +import 'package:get/get.dart'; +import '../../../models/colors/app_colors.dart'; +import '../../../services/get/theme_controller.dart'; class ServerInfoDialog { static Future show(BuildContext context, {Map? data}) { @@ -13,236 +15,241 @@ class ServerInfoDialog { final latency = network?['latency'] as List?; final serverResponseTime = network?['server_response_time']; + final ThemeController themeController = Get.find(); + return showDialog( context: context, builder: (BuildContext context) { - return Dialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - child: Container( - constraints: const BoxConstraints(maxWidth: 340), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: AppConstants.primaryColor, - borderRadius: const BorderRadius.vertical( - top: Radius.circular(16), + return Obx(() { + final isDark = themeController.isDarkMode; + return Dialog( + backgroundColor: AppColors.surface, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + child: Container( + constraints: const BoxConstraints(maxWidth: 340), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: const EdgeInsets.all(20), + decoration: BoxDecoration( + color: AppColors.primary, + borderRadius: const BorderRadius.vertical( + top: Radius.circular(16), + ), ), - ), - child: Row( - children: [ - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: Colors.white.withValues(alpha: 0.2), - borderRadius: BorderRadius.circular(8), - ), - child: const Icon( - Icons.cloud_outlined, - color: Colors.white, - size: 20, - ), - ), - const SizedBox(width: 12), - const Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '广州 server-ls', - style: TextStyle( - color: Colors.white, - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - SizedBox(height: 2), - Text( - '服务器信息', - style: TextStyle( - color: Colors.white70, - fontSize: 12, - ), - ), - ], - ), - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.all(20), - child: Column( - children: [ - _buildInfoCard( - icon: Icons.schedule, - iconColor: const Color(0xFF007AFF), - title: '服务器时间', - content: timestamp?['datetime'] ?? '--', - ), - const SizedBox(height: 12), - _buildInfoCard( - icon: Icons.speed, - iconColor: const Color(0xFF34C759), - title: '服务器负载', - content: - '1分钟: ${_formatLoad(load?['1min'])}\n5分钟: ${_formatLoad(load?['5min'])}\n15分钟: ${_formatLoad(load?['15min'])}', - ), - const SizedBox(height: 12), - _buildInfoCard( - icon: Icons.bolt, - iconColor: const Color(0xFFFF9500), - title: '服务器响应', - content: '${serverResponseTime ?? '--'} ms', - trailing: _buildResponseTimeIndicator( - serverResponseTime, - ), - ), - if (latency != null && latency.isNotEmpty) ...[ - const SizedBox(height: 16), + child: Row( + children: [ Container( - padding: const EdgeInsets.all(12), + padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: const Color(0xFFF2F2F7), - borderRadius: BorderRadius.circular(12), + color: Colors.white.withValues(alpha: 0.2), + borderRadius: BorderRadius.circular(8), ), + child: const Icon( + Icons.cloud_outlined, + color: Colors.white, + size: 20, + ), + ), + const SizedBox(width: 12), + Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - Icon( - Icons.public, - size: 16, - color: Colors.grey[600], - ), - const SizedBox(width: 8), - Text( - '网络延迟', - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 14, - color: Colors.grey[700], - ), - ), - ], + const Text( + '广州 server-ls', + style: TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 2), + Text( + '服务器信息', + style: TextStyle( + color: Colors.white.withValues(alpha: 0.7), + fontSize: 12, + ), ), - const SizedBox(height: 12), - ...latency.map((item) { - final host = item['host'] as String?; - final ip = item['ip'] as String?; - final lat = item['latency']; - final status = item['status'] as String?; - final isOnline = status == 'online'; - - return Padding( - padding: const EdgeInsets.only(bottom: 8), - child: Row( - children: [ - Container( - width: 8, - height: 8, - decoration: BoxDecoration( - color: isOnline - ? const Color(0xFF34C759) - : const Color(0xFFFF3B30), - shape: BoxShape.circle, - ), - ), - const SizedBox(width: 8), - Expanded( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - host ?? '--', - style: const TextStyle( - fontSize: 13, - fontWeight: FontWeight.w500, - ), - ), - Text( - ip ?? '--', - style: TextStyle( - fontSize: 11, - color: Colors.grey[500], - ), - ), - ], - ), - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), - decoration: BoxDecoration( - color: isOnline - ? const Color( - 0xFF34C759, - ).withValues(alpha: 0.1) - : const Color( - 0xFFFF3B30, - ).withValues(alpha: 0.1), - borderRadius: BorderRadius.circular( - 8, - ), - ), - child: Text( - isOnline ? '$lat ms' : '离线', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: isOnline - ? const Color(0xFF34C759) - : const Color(0xFFFF3B30), - ), - ), - ), - ], - ), - ); - }), ], ), ), ], - ], + ), ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(20, 0, 20, 20), - child: SizedBox( - width: double.infinity, - child: TextButton( - onPressed: () => Navigator.of(context).pop(), - style: TextButton.styleFrom( - backgroundColor: const Color(0xFFF2F2F7), - padding: const EdgeInsets.symmetric(vertical: 14), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), + Padding( + padding: const EdgeInsets.all(20), + child: Column( + children: [ + _buildInfoCard( + icon: Icons.schedule, + iconColor: AppColors.iosBlue, + title: '服务器时间', + content: timestamp?['datetime'] ?? '--', ), - ), - child: const Text( - '关闭', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Color(0xFF007AFF), + const SizedBox(height: 12), + _buildInfoCard( + icon: Icons.speed, + iconColor: AppColors.iosGreen, + title: '服务器负载', + content: + '1分钟: ${_formatLoad(load?['1min'])}\n5分钟: ${_formatLoad(load?['5min'])}\n15分钟: ${_formatLoad(load?['15min'])}', + ), + const SizedBox(height: 12), + _buildInfoCard( + icon: Icons.bolt, + iconColor: AppColors.iosOrange, + title: '服务器响应', + content: '${serverResponseTime ?? '--'} ms', + trailing: _buildResponseTimeIndicator( + serverResponseTime, + ), + ), + if (latency != null && latency.isNotEmpty) ...[ + const SizedBox(height: 16), + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: AppColors.card, + borderRadius: BorderRadius.circular(12), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon( + Icons.public, + size: 16, + color: AppColors.tertiaryText, + ), + const SizedBox(width: 8), + Text( + '网络延迟', + style: TextStyle( + fontWeight: FontWeight.w600, + fontSize: 14, + color: AppColors.secondaryText, + ), + ), + ], + ), + const SizedBox(height: 12), + ...latency.map((item) { + final host = item['host'] as String?; + final ip = item['ip'] as String?; + final lat = item['latency']; + final status = item['status'] as String?; + final isOnline = status == 'online'; + + return Padding( + padding: const EdgeInsets.only(bottom: 8), + child: Row( + children: [ + Container( + width: 8, + height: 8, + decoration: BoxDecoration( + color: isOnline + ? AppColors.iosGreen + : AppColors.iosRed, + shape: BoxShape.circle, + ), + ), + const SizedBox(width: 8), + Expanded( + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + host ?? '--', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w500, + color: AppColors.primaryText, + ), + ), + Text( + ip ?? '--', + style: TextStyle( + fontSize: 11, + color: AppColors.tertiaryText, + ), + ), + ], + ), + ), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 4, + ), + decoration: BoxDecoration( + color: isOnline + ? AppColors.iosGreen + .withValues(alpha: 0.1) + : AppColors.iosRed + .withValues(alpha: 0.1), + borderRadius: BorderRadius.circular( + 8, + ), + ), + child: Text( + isOnline ? '$lat ms' : '离线', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: isOnline + ? AppColors.iosGreen + : AppColors.iosRed, + ), + ), + ), + ], + ), + ); + }), + ], + ), + ), + ], + ], + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(20, 0, 20, 20), + child: SizedBox( + width: double.infinity, + child: TextButton( + onPressed: () => Navigator.of(context).pop(), + style: TextButton.styleFrom( + backgroundColor: AppColors.card, + padding: const EdgeInsets.symmetric(vertical: 14), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: Text( + '关闭', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: AppColors.primary, + ), ), ), ), ), - ), - ], + ], + ), ), - ), - ); + ); + }); }, ); } @@ -257,7 +264,7 @@ class ServerInfoDialog { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( - color: const Color(0xFFF2F2F7), + color: AppColors.card, borderRadius: BorderRadius.circular(12), ), child: Row( @@ -277,14 +284,18 @@ class ServerInfoDialog { children: [ Text( title, - style: TextStyle(fontSize: 12, color: Colors.grey[600]), + style: TextStyle( + fontSize: 12, + color: AppColors.tertiaryText, + ), ), const SizedBox(height: 2), Text( content, - style: const TextStyle( + style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, + color: AppColors.primaryText, ), ), ], @@ -327,16 +338,16 @@ class ServerInfoDialog { Color color; String label; if (time < 100) { - color = const Color(0xFF34C759); + color = AppColors.iosGreen; label = '极快'; } else if (time < 300) { - color = const Color(0xFF34C759); + color = AppColors.iosGreen; label = '快速'; } else if (time < 500) { - color = const Color(0xFFFF9500); + color = AppColors.iosOrange; label = '正常'; } else { - color = const Color(0xFFFF3B30); + color = AppColors.iosRed; label = '较慢'; } diff --git a/lib/views/profile/expand/manu-script.dart b/lib/views/profile/expand/manu-script.dart index a7380cc..6ed21eb 100644 --- a/lib/views/profile/expand/manu-script.dart +++ b/lib/views/profile/expand/manu-script.dart @@ -1,9 +1,11 @@ import 'dart:io' as io; import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../../constants/app_constants.dart'; import '../../../utils/http/http_client.dart'; +import '../../../services/get/theme_controller.dart'; import 'tougao.dart'; /// 时间: 2026-03-30 @@ -24,6 +26,7 @@ class _ManuscriptPageState extends State { final _urlController = TextEditingController(); final _keywordsController = TextEditingController(); final _introduceController = TextEditingController(); + final ThemeController _themeController = Get.find(); List> _categories = []; String? _selectedCategory; @@ -356,26 +359,28 @@ class _ManuscriptPageState extends State { @override Widget build(BuildContext context) { + final isDark = _themeController.isDarkMode; + final primaryColor = _themeController.currentThemeColor; + return Scaffold( - backgroundColor: const Color(0xFFF5F5F5), + backgroundColor: isDark + ? const Color(0xFF1A1A1A) + : const Color(0xFFF5F5F5), appBar: AppBar( - title: const Text( + title: Text( '📝 诗词投稿', - style: TextStyle( - color: AppConstants.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold), ), - backgroundColor: Colors.white, + backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, elevation: 0, centerTitle: true, leading: IconButton( - icon: const Icon(Icons.arrow_back, color: AppConstants.primaryColor), + icon: Icon(Icons.arrow_back, color: primaryColor), onPressed: () => Navigator.of(context).pop(), ), actions: [ IconButton( - icon: const Icon(Icons.history, color: AppConstants.primaryColor), + icon: Icon(Icons.history, color: primaryColor), tooltip: '投稿记录', onPressed: () { Navigator.push( @@ -405,14 +410,14 @@ class _ManuscriptPageState extends State { } Widget _buildHeaderCard() { + final isDark = _themeController.isDarkMode; + final primaryColor = _themeController.currentThemeColor; + return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( gradient: LinearGradient( - colors: [ - AppConstants.primaryColor.withAlpha(30), - AppConstants.primaryColor.withAlpha(10), - ], + colors: [primaryColor.withAlpha(30), primaryColor.withAlpha(10)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), @@ -423,28 +428,31 @@ class _ManuscriptPageState extends State { Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( - color: Colors.white, + color: isDark ? const Color(0xFF2A2A2A) : Colors.white, borderRadius: BorderRadius.circular(12), ), - child: const Icon( - Icons.edit_note, - color: AppConstants.primaryColor, - size: 32, - ), + child: Icon(Icons.edit_note, color: primaryColor, size: 32), ), const SizedBox(width: 16), - const Expanded( + Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '收录经典诗词', - style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: isDark ? Colors.white : Colors.black87, + ), ), - SizedBox(height: 4), + const SizedBox(height: 4), Text( '支持原创和古诗,传承中华文化', - style: TextStyle(fontSize: 14, color: Colors.grey), + style: TextStyle( + fontSize: 14, + color: isDark ? Colors.grey[400] : Colors.grey, + ), ), ], ), @@ -455,13 +463,15 @@ class _ManuscriptPageState extends State { } Widget _buildFormCard() { + final isDark = _themeController.isDarkMode; + return Container( decoration: BoxDecoration( - color: Colors.white, + color: isDark ? const Color(0xFF2A2A2A) : Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( - color: Colors.black.withAlpha(10), + color: Colors.black.withAlpha(isDark ? 30 : 10), blurRadius: 10, offset: const Offset(0, 2), ), @@ -493,13 +503,19 @@ class _ManuscriptPageState extends State { } Widget _buildSectionHeader(String title) { + final isDark = _themeController.isDarkMode; + return Padding( padding: const EdgeInsets.all(16), child: Row( children: [ Text( title, - style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + color: isDark ? Colors.white : Colors.black87, + ), ), ], ), @@ -507,14 +523,20 @@ class _ManuscriptPageState extends State { } Widget _buildNameField() { + final isDark = _themeController.isDarkMode; + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ - const Text( + Text( '参考语句', - style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: isDark ? Colors.white : Colors.black87, + ), ), const Text(' *', style: TextStyle(color: AppConstants.errorColor)), const Spacer(), @@ -531,7 +553,22 @@ class _ManuscriptPageState extends State { controller: _nameController, decoration: InputDecoration( hintText: '如:纤云弄巧,飞星传恨', - border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + hintStyle: TextStyle( + color: isDark ? Colors.grey[500] : Colors.grey[400], + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: isDark ? Colors.grey[600]! : Colors.grey[300]!, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: _themeController.currentThemeColor, + width: 2, + ), + ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12, @@ -545,6 +582,7 @@ class _ManuscriptPageState extends State { ) : null, ), + style: TextStyle(color: isDark ? Colors.white : Colors.black87), validator: (value) { if (value == null || value.trim().isEmpty) { return '请输入参考语句'; @@ -594,8 +632,15 @@ class _ManuscriptPageState extends State { ), TextButton.icon( onPressed: _isCheckingName ? null : _checkName, - icon: const Icon(Icons.search, size: 18), - label: const Text('检测是否存在'), + icon: Icon( + Icons.search, + size: 18, + color: _themeController.currentThemeColor, + ), + label: Text( + '检测是否存在', + style: TextStyle(color: _themeController.currentThemeColor), + ), ), ], ), @@ -642,16 +687,22 @@ class _ManuscriptPageState extends State { } Widget _buildCategoryField() { + final isDark = _themeController.isDarkMode; + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Row( + Row( children: [ Text( '分类', - style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: isDark ? Colors.white : Colors.black87, + ), ), - Text(' *', style: TextStyle(color: AppConstants.errorColor)), + const Text(' *', style: TextStyle(color: AppConstants.errorColor)), ], ), const SizedBox(height: 8), @@ -659,7 +710,22 @@ class _ManuscriptPageState extends State { value: _selectedCategory, decoration: InputDecoration( hintText: '请选择分类', - border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + hintStyle: TextStyle( + color: isDark ? Colors.grey[500] : Colors.grey[400], + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: isDark ? Colors.grey[600]! : Colors.grey[300]!, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: _themeController.currentThemeColor, + width: 2, + ), + ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12, @@ -668,12 +734,17 @@ class _ManuscriptPageState extends State { items: _categories.map((cat) { return DropdownMenuItem( value: cat['catename'] as String, - child: Text(cat['catename'] as String), + child: Text( + cat['catename'] as String, + style: TextStyle(color: isDark ? Colors.white : Colors.black87), + ), ); }).toList(), onChanged: (value) { setState(() => _selectedCategory = value); }, + dropdownColor: isDark ? const Color(0xFF333333) : Colors.white, + style: TextStyle(color: isDark ? Colors.white : Colors.black87), validator: (value) { if (value == null || value.isEmpty) { return '请选择分类'; @@ -686,16 +757,22 @@ class _ManuscriptPageState extends State { } Widget _buildUrlField() { + final isDark = _themeController.isDarkMode; + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Row( + Row( children: [ Text( '诗人和标题', - style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: isDark ? Colors.white : Colors.black87, + ), ), - Text(' *', style: TextStyle(color: AppConstants.errorColor)), + const Text(' *', style: TextStyle(color: AppConstants.errorColor)), ], ), const SizedBox(height: 8), @@ -703,12 +780,28 @@ class _ManuscriptPageState extends State { controller: _urlController, decoration: InputDecoration( hintText: '如:李白 静夜思', - border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + hintStyle: TextStyle( + color: isDark ? Colors.grey[500] : Colors.grey[400], + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: isDark ? Colors.grey[600]! : Colors.grey[300]!, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: _themeController.currentThemeColor, + width: 2, + ), + ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12, ), ), + style: TextStyle(color: isDark ? Colors.white : Colors.black87), validator: (value) { if (value == null || value.trim().isEmpty) { return '请输入诗人和标题'; @@ -721,16 +814,22 @@ class _ManuscriptPageState extends State { } Widget _buildKeywordsField() { + final isDark = _themeController.isDarkMode; + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Row( + Row( children: [ Text( '关键词', - style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: isDark ? Colors.white : Colors.black87, + ), ), - Text(' *', style: TextStyle(color: AppConstants.errorColor)), + const Text(' *', style: TextStyle(color: AppConstants.errorColor)), ], ), const SizedBox(height: 8), @@ -738,12 +837,28 @@ class _ManuscriptPageState extends State { controller: _keywordsController, decoration: InputDecoration( hintText: '用逗号分隔,如:思乡,月亮,唐诗', - border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + hintStyle: TextStyle( + color: isDark ? Colors.grey[500] : Colors.grey[400], + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: isDark ? Colors.grey[600]! : Colors.grey[300]!, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: _themeController.currentThemeColor, + width: 2, + ), + ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12, ), ), + style: TextStyle(color: isDark ? Colors.white : Colors.black87), validator: (value) { if (value == null || value.trim().isEmpty) { return '请输入关键词'; @@ -756,16 +871,22 @@ class _ManuscriptPageState extends State { } Widget _buildIntroduceField() { + final isDark = _themeController.isDarkMode; + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Row( + Row( children: [ Text( '诗词介绍', - style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: isDark ? Colors.white : Colors.black87, + ), ), - Text(' *', style: TextStyle(color: AppConstants.errorColor)), + const Text(' *', style: TextStyle(color: AppConstants.errorColor)), ], ), const SizedBox(height: 8), @@ -774,9 +895,25 @@ class _ManuscriptPageState extends State { maxLines: 5, decoration: InputDecoration( hintText: '会说就多说几句...', - border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)), + hintStyle: TextStyle( + color: isDark ? Colors.grey[500] : Colors.grey[400], + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: isDark ? Colors.grey[600]! : Colors.grey[300]!, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: _themeController.currentThemeColor, + width: 2, + ), + ), contentPadding: const EdgeInsets.all(16), ), + style: TextStyle(color: isDark ? Colors.white : Colors.black87), validator: (value) { if (value == null || value.trim().isEmpty) { return '请输入诗词介绍'; @@ -789,19 +926,18 @@ class _ManuscriptPageState extends State { } Widget _buildSubmitButton() { + final primaryColor = _themeController.currentThemeColor; + return Container( height: 56, decoration: BoxDecoration( gradient: LinearGradient( - colors: [ - AppConstants.primaryColor, - AppConstants.primaryColor.withAlpha(200), - ], + colors: [primaryColor, primaryColor.withAlpha(200)], ), borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( - color: AppConstants.primaryColor.withAlpha(50), + color: primaryColor.withAlpha(50), blurRadius: 10, offset: const Offset(0, 4), ), @@ -845,10 +981,13 @@ class _ManuscriptPageState extends State { } Widget _buildTipsCard() { + final isDark = _themeController.isDarkMode; + final primaryColor = _themeController.currentThemeColor; + return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: Colors.blue[50], + color: isDark ? primaryColor.withAlpha(20) : primaryColor.withAlpha(10), borderRadius: BorderRadius.circular(12), ), child: Column( @@ -856,14 +995,14 @@ class _ManuscriptPageState extends State { children: [ Row( children: [ - Icon(Icons.lightbulb_outline, color: Colors.blue[700], size: 20), + Icon(Icons.lightbulb_outline, color: primaryColor, size: 20), const SizedBox(width: 8), Text( '投稿提示', style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, - color: Colors.blue[700], + color: primaryColor, ), ), ], @@ -873,7 +1012,7 @@ class _ManuscriptPageState extends State { '• 支持原创诗词和经典古诗\n• 相似度超过80%将无法提交\n• 提交后等待审核通过\n• 平台信息自动识别:${_getPlatform()}', style: TextStyle( fontSize: 13, - color: Colors.blue[700], + color: isDark ? Colors.grey[300] : primaryColor, height: 1.5, ), ), diff --git a/lib/views/profile/expand/tougao.dart b/lib/views/profile/expand/tougao.dart index b9d24ef..f35c930 100644 --- a/lib/views/profile/expand/tougao.dart +++ b/lib/views/profile/expand/tougao.dart @@ -145,7 +145,7 @@ class _TougaoPageState extends State { appBar: AppBar( title: Text( '投稿记录', - style: TextStyle(color: isDark ? Colors.white : Colors.black87), + style: TextStyle(color: _themeController.currentThemeColor), ), backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, elevation: 0, @@ -154,7 +154,7 @@ class _TougaoPageState extends State { IconButton( icon: Icon( Icons.delete_sweep_outlined, - color: isDark ? Colors.white : Colors.black87, + color: _themeController.currentThemeColor, ), onPressed: _clearAllRecords, tooltip: '清空记录', @@ -230,14 +230,16 @@ class _TougaoPageState extends State { Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.2), + color: _themeController.currentThemeColor.withValues( + alpha: 0.2, + ), borderRadius: BorderRadius.circular(8), ), child: Text( record.catename, style: TextStyle( fontSize: 12, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, fontWeight: FontWeight.w500, ), ), diff --git a/lib/views/profile/expand/vote.dart b/lib/views/profile/expand/vote.dart index c14a43b..7d70a91 100644 --- a/lib/views/profile/expand/vote.dart +++ b/lib/views/profile/expand/vote.dart @@ -158,7 +158,7 @@ class _VotePageState extends State { ), backgroundColor: isDark ? const Color(0xFF2A2A2A) - : AppConstants.primaryColor, + : _themeController.currentThemeColor, elevation: 0, actions: [ if (_isLoggedIn) @@ -216,7 +216,7 @@ class _VotePageState extends State { onPressed: _loadVoteList, style: ElevatedButton.styleFrom( backgroundColor: - AppConstants.primaryColor, + _themeController.currentThemeColor, ), child: const Text('刷新'), ), @@ -321,14 +321,14 @@ class _VotePageState extends State { Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: _themeController.currentThemeColor.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(8), ), child: Icon( vote.isSingleChoice ? Icons.radio_button_checked : Icons.check_box, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, size: 20, ), ), @@ -805,7 +805,7 @@ class _VoteDetailPageState extends State { ), backgroundColor: isDark ? const Color(0xFF2A2A2A) - : AppConstants.primaryColor, + : _themeController.currentThemeColor, elevation: 0, ), body: _isLoading @@ -821,10 +821,10 @@ class _VoteDetailPageState extends State { decoration: BoxDecoration( gradient: LinearGradient( colors: [ - AppConstants.primaryColor.withValues( + _themeController.currentThemeColor.withValues( alpha: isDark ? 0.3 : 0.1, ), - AppConstants.primaryColor.withValues( + _themeController.currentThemeColor.withValues( alpha: isDark ? 0.15 : 0.05, ), ], @@ -841,7 +841,7 @@ class _VoteDetailPageState extends State { Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues( + color: _themeController.currentThemeColor.withValues( alpha: 0.15, ), borderRadius: BorderRadius.circular(10), @@ -850,7 +850,7 @@ class _VoteDetailPageState extends State { widget.vote.isSingleChoice ? Icons.radio_button_checked : Icons.check_box, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, size: 24, ), ), @@ -1134,13 +1134,13 @@ class _VoteDetailPageState extends State { decoration: BoxDecoration( border: Border.all( color: isSelected - ? AppConstants.primaryColor + ? _themeController.currentThemeColor : (isDark ? Colors.grey[600]! : Colors.grey[300]!), width: 2, ), borderRadius: BorderRadius.circular(12), color: isSelected - ? AppConstants.primaryColor.withValues(alpha: 0.05) + ? _themeController.currentThemeColor.withValues(alpha: 0.05) : (isDark ? const Color(0xFF2A2A2A) : Colors.white), ), child: InkWell( @@ -1159,7 +1159,7 @@ class _VoteDetailPageState extends State { ? Icons.check_box : Icons.check_box_outline_blank), color: isSelected - ? AppConstants.primaryColor + ? _themeController.currentThemeColor : (isDark ? Colors.grey[400] : Colors.grey), ), const SizedBox(width: 12), @@ -1175,7 +1175,7 @@ class _VoteDetailPageState extends State { ? FontWeight.bold : FontWeight.normal, color: isSelected - ? AppConstants.primaryColor + ? _themeController.currentThemeColor : (isDark ? Colors.white : Colors.black), ), ), @@ -1207,7 +1207,7 @@ class _VoteDetailPageState extends State { child: ElevatedButton( onPressed: _isSubmitting ? null : _submitVote, style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: _themeController.currentThemeColor, padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), @@ -1309,7 +1309,7 @@ class _VoteDetailPageState extends State { icon: Icons.poll, label: '总票数', value: '${_voteResult!.totalVotes}', - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, isDark: isDark, ), Container( @@ -1446,7 +1446,7 @@ class _VoteDetailPageState extends State { decoration: BoxDecoration( color: isVoted ? AppConstants.successColor.withValues(alpha: 0.1) - : AppConstants.primaryColor.withValues(alpha: 0.1), + : _themeController.currentThemeColor.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(12), ), child: Text( @@ -1454,7 +1454,7 @@ class _VoteDetailPageState extends State { style: TextStyle( color: isVoted ? AppConstants.successColor - : AppConstants.primaryColor, + : _themeController.currentThemeColor, fontSize: 14, fontWeight: FontWeight.bold, ), @@ -1476,7 +1476,7 @@ class _VoteDetailPageState extends State { valueColor: AlwaysStoppedAnimation( isVoted ? AppConstants.successColor - : AppConstants.primaryColor, + : _themeController.currentThemeColor, ), minHeight: 8, ), diff --git a/lib/views/profile/guide/app-data.dart b/lib/views/profile/guide/app-data.dart index 7f698cf..518c67b 100644 --- a/lib/views/profile/guide/app-data.dart +++ b/lib/views/profile/guide/app-data.dart @@ -205,7 +205,7 @@ class _AppDataPageState extends State { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: const Text('配置数据已清空,请重新启动应用'), - backgroundColor: AppConstants.primaryColor, + backgroundColor: _themeController.currentThemeColor, duration: const Duration(seconds: 3), ), ); @@ -348,7 +348,7 @@ class _AppDataPageState extends State { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: const Text('缓存已清空'), - backgroundColor: AppConstants.primaryColor, + backgroundColor: _themeController.currentThemeColor, ), ); } @@ -415,7 +415,7 @@ class _AppDataPageState extends State { title.contains('⚠️') ? Icons.warning : Icons.help_outline, color: title.contains('⚠️') ? Colors.orange - : AppConstants.primaryColor, + : _themeController.currentThemeColor, ), const SizedBox(width: 8), Expanded(child: Text(title, style: const TextStyle(fontSize: 18))), @@ -432,7 +432,7 @@ class _AppDataPageState extends State { style: ElevatedButton.styleFrom( backgroundColor: title.contains('危险') || title.contains('再次') ? Colors.red - : AppConstants.primaryColor, + : _themeController.currentThemeColor, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), @@ -489,7 +489,7 @@ class _AppDataPageState extends State { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), - backgroundColor: AppConstants.primaryColor, + backgroundColor: _themeController.currentThemeColor, ), ); } @@ -498,6 +498,7 @@ class _AppDataPageState extends State { Widget build(BuildContext context) { return Obx(() { final isDark = _themeController.isDarkMode; + final primaryColor = _themeController.currentThemeColor; return Scaffold( backgroundColor: isDark @@ -508,9 +509,7 @@ class _AppDataPageState extends State { '应用数据', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold), ), - backgroundColor: isDark - ? const Color(0xFF2A2A2A) - : AppConstants.primaryColor, + backgroundColor: isDark ? const Color(0xFF2A2A2A) : primaryColor, iconTheme: IconThemeData(color: Colors.white), ), body: _isLoading @@ -551,14 +550,14 @@ class _AppDataPageState extends State { Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: _themeController.currentThemeColor.withAlpha(10), borderRadius: const BorderRadius.vertical( top: Radius.circular(16), ), ), child: Row( children: [ - Icon(Icons.storage, color: AppConstants.primaryColor), + Icon(Icons.storage, color: _themeController.currentThemeColor), const SizedBox(width: 8), const Text( '数据概览', diff --git a/lib/views/profile/guide/beginner_page.dart b/lib/views/profile/guide/beginner_page.dart index 3e0fe5f..a0802ca 100644 --- a/lib/views/profile/guide/beginner_page.dart +++ b/lib/views/profile/guide/beginner_page.dart @@ -24,7 +24,7 @@ class _BeginnerPageState extends State 'title': '首页功能', 'icon': Icons.home, 'emoji': '🏠', - 'color': AppConstants.primaryColor, + 'color': Colors.blue, 'features': [ '精美卡片展示', '智能推荐:根据时间和情景推荐合适的诗词', @@ -271,6 +271,7 @@ class _BeginnerPageState extends State Widget build(BuildContext context) { return Obx(() { final isDark = _themeController.isDarkMode; + final primaryColor = _themeController.currentThemeColor; return Scaffold( backgroundColor: isDark ? const Color(0xFF1A1A1A) : Colors.grey[50], body: Stack( @@ -286,13 +287,13 @@ class _BeginnerPageState extends State style: TextStyle( fontWeight: FontWeight.bold, fontSize: 17, - color: AppConstants.primaryColor, + color: primaryColor, ), ), backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, - foregroundColor: AppConstants.primaryColor, + foregroundColor: primaryColor, elevation: 0, centerTitle: true, floating: true, @@ -301,7 +302,7 @@ class _BeginnerPageState extends State actions: [ IconButton( icon: const Icon(Icons.help_outline), - color: AppConstants.primaryColor, + color: primaryColor, onPressed: () { Navigator.push( context, @@ -497,7 +498,7 @@ class _BeginnerPageState extends State Icon( Icons.visibility_outlined, size: 16, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, ), const SizedBox(width: 6), Text( @@ -505,7 +506,7 @@ class _BeginnerPageState extends State style: TextStyle( fontSize: 13, fontWeight: FontWeight.w600, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, ), ), ], @@ -532,13 +533,13 @@ class _BeginnerPageState extends State width: 32, height: 32, decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: _themeController.currentThemeColor.withAlpha(10), borderRadius: BorderRadius.circular(8), ), child: Icon( Icons.book, size: 18, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, ), ), const SizedBox(width: 10), @@ -689,7 +690,7 @@ class _BeginnerPageState extends State width: 48, height: 48, decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.2), + color: _themeController.currentThemeColor.withAlpha(20), borderRadius: BorderRadius.circular(24), ), child: const Center( @@ -760,14 +761,14 @@ class _BeginnerPageState extends State color: isDark ? const Color(0xFF2A2A2A) : Colors.white, borderRadius: BorderRadius.circular(16), border: Border.all( - color: AppConstants.primaryColor.withValues(alpha: 0.3), + color: _themeController.currentThemeColor.withAlpha(30), ), ), child: Text( text, style: TextStyle( fontSize: 12, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, fontWeight: FontWeight.w500, ), ), @@ -812,7 +813,7 @@ class _BeginnerPageState extends State style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, ), ), const SizedBox(height: 2), @@ -873,12 +874,12 @@ class _BeginnerPageState extends State width: 8, height: 40, decoration: BoxDecoration( - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, borderRadius: BorderRadius.circular(4), boxShadow: [ BoxShadow( - color: AppConstants.primaryColor.withValues( - alpha: 0.3, + color: _themeController.currentThemeColor.withAlpha( + 30, ), blurRadius: 8, offset: const Offset(0, 2), @@ -895,11 +896,11 @@ class _BeginnerPageState extends State duration: const Duration(milliseconds: 200), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, borderRadius: BorderRadius.circular(8), boxShadow: [ BoxShadow( - color: AppConstants.primaryColor.withValues(alpha: 0.2), + color: _themeController.currentThemeColor.withAlpha(20), blurRadius: 4, offset: const Offset(0, 2), ), diff --git a/lib/views/profile/guide/permission.dart b/lib/views/profile/guide/permission.dart index 0971a12..8ac560d 100644 --- a/lib/views/profile/guide/permission.dart +++ b/lib/views/profile/guide/permission.dart @@ -41,6 +41,7 @@ class _PermissionPageState extends State { Widget build(BuildContext context) { return Obx(() { final isDark = _themeController.isDarkMode; + final primaryColor = _themeController.currentThemeColor; return Scaffold( backgroundColor: isDark ? const Color(0xFF1A1A1A) @@ -49,7 +50,7 @@ class _PermissionPageState extends State { title: Text( '权限管理', style: TextStyle( - color: isDark ? Colors.white : AppConstants.primaryColor, + color: isDark ? Colors.white : primaryColor, fontWeight: FontWeight.bold, ), ), @@ -59,7 +60,7 @@ class _PermissionPageState extends State { leading: IconButton( icon: Icon( Icons.arrow_back, - color: isDark ? Colors.white : AppConstants.primaryColor, + color: isDark ? Colors.white : primaryColor, ), onPressed: () => Navigator.pop(context), ), @@ -67,7 +68,7 @@ class _PermissionPageState extends State { IconButton( icon: Icon( Icons.info_outline, - color: isDark ? Colors.white : AppConstants.primaryColor, + color: isDark ? Colors.white : primaryColor, ), onPressed: _showPermissionInfoDialog, ), @@ -118,6 +119,14 @@ class _PermissionPageState extends State { null, isDark, ), + _buildPermissionItem( + '设备标识', + '获取设备唯一标识', + Icons.person, + _clipboardEnabled, + null, + isDark, + ), ], isDark), const SizedBox(height: 16), _buildPermissionGroup('权限说明', [ @@ -126,6 +135,7 @@ class _PermissionPageState extends State { _buildInfoItem('剪切板', '用于复制诗词内容,方便用户分享和记录。', isDark), _buildInfoItem('播放声音', '用于主页点击提示音,提升用户体验。', isDark), _buildInfoItem('分享能力', '用于分享诗词内容到社交媒体平台。', isDark), + _buildInfoItem('设备标识', '用于唯一标识设备,确保用户数据安全。', isDark), ], isDark), const SizedBox(height: 16), _buildSandboxInfoCard(isDark), @@ -161,14 +171,14 @@ class _PermissionPageState extends State { children: [ Icon( Icons.security, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, size: 20, ), const SizedBox(width: 8), Text( title, style: TextStyle( - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, fontSize: 16, fontWeight: FontWeight.bold, ), @@ -199,10 +209,14 @@ class _PermissionPageState extends State { width: 40, height: 40, decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: _themeController.currentThemeColor.withAlpha(10), borderRadius: BorderRadius.circular(12), ), - child: Icon(icon, color: AppConstants.primaryColor, size: 20), + child: Icon( + icon, + color: _themeController.currentThemeColor, + size: 20, + ), ), const SizedBox(width: 12), Expanded( @@ -271,7 +285,7 @@ class _PermissionPageState extends State { height: 4, margin: const EdgeInsets.only(top: 6), decoration: BoxDecoration( - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, borderRadius: BorderRadius.circular(2), ), ), @@ -325,12 +339,16 @@ class _PermissionPageState extends State { padding: const EdgeInsets.all(16), child: Row( children: [ - Icon(Icons.build, color: AppConstants.primaryColor, size: 20), + Icon( + Icons.build, + color: _themeController.currentThemeColor, + size: 20, + ), const SizedBox(width: 8), Text( '项目补充完善', style: TextStyle( - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, fontSize: 16, fontWeight: FontWeight.bold, ), @@ -389,10 +407,14 @@ class _PermissionPageState extends State { width: 40, height: 40, decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: _themeController.currentThemeColor.withAlpha(10), borderRadius: BorderRadius.circular(12), ), - child: Icon(icon, color: AppConstants.primaryColor, size: 20), + child: Icon( + icon, + color: _themeController.currentThemeColor, + size: 20, + ), ), const SizedBox(width: 12), Expanded( @@ -435,7 +457,7 @@ class _PermissionPageState extends State { shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), title: Row( children: [ - Icon(Icons.feedback, color: AppConstants.primaryColor), + Icon(Icons.feedback, color: _themeController.currentThemeColor), const SizedBox(width: 8), const Text('用户反馈'), ], @@ -456,7 +478,7 @@ class _PermissionPageState extends State { TextSpan( text: '情景诗词', style: TextStyle( - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, fontWeight: FontWeight.bold, ), ), @@ -469,7 +491,7 @@ class _PermissionPageState extends State { '记得五星好评 ⭐', style: TextStyle( fontSize: 14, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, fontWeight: FontWeight.w500, ), ), @@ -480,7 +502,7 @@ class _PermissionPageState extends State { onPressed: () => Navigator.pop(context), child: Text( '确定', - style: TextStyle(color: AppConstants.primaryColor), + style: TextStyle(color: _themeController.currentThemeColor), ), ), ], @@ -495,7 +517,7 @@ class _PermissionPageState extends State { shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), title: Row( children: [ - Icon(Icons.lightbulb, color: AppConstants.primaryColor), + Icon(Icons.lightbulb, color: _themeController.currentThemeColor), const SizedBox(width: 8), const Text('功能建议'), ], @@ -516,7 +538,7 @@ class _PermissionPageState extends State { TextSpan( text: '情景诗词', style: TextStyle( - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, fontWeight: FontWeight.bold, ), ), @@ -529,7 +551,7 @@ class _PermissionPageState extends State { '记得五星好评 ⭐', style: TextStyle( fontSize: 14, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, fontWeight: FontWeight.w500, ), ), @@ -540,7 +562,7 @@ class _PermissionPageState extends State { onPressed: () => Navigator.pop(context), child: Text( '确定', - style: TextStyle(color: AppConstants.primaryColor), + style: TextStyle(color: _themeController.currentThemeColor), ), ), ], @@ -555,7 +577,7 @@ class _PermissionPageState extends State { shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), title: Row( children: [ - Icon(Icons.info, color: AppConstants.primaryColor), + Icon(Icons.info, color: _themeController.currentThemeColor), const SizedBox(width: 8), const Text('基础权限说明'), ], @@ -569,7 +591,7 @@ class _PermissionPageState extends State { onPressed: () => Navigator.pop(context), child: Text( '确定', - style: TextStyle(color: AppConstants.primaryColor), + style: TextStyle(color: _themeController.currentThemeColor), ), ), ], @@ -599,12 +621,12 @@ class _PermissionPageState extends State { Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: _themeController.currentThemeColor.withAlpha(10), borderRadius: BorderRadius.circular(8), ), child: Icon( Icons.shield, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, size: 20, ), ), @@ -612,7 +634,7 @@ class _PermissionPageState extends State { Text( '沙盒运行说明', style: TextStyle( - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, fontSize: 16, fontWeight: FontWeight.bold, ), @@ -652,14 +674,14 @@ class _PermissionPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - width: 4, - height: 4, - margin: const EdgeInsets.only(top: 8), - decoration: BoxDecoration( - color: AppConstants.primaryColor, - borderRadius: BorderRadius.circular(2), + width: 4, + height: 4, + margin: const EdgeInsets.only(top: 8), + decoration: BoxDecoration( + color: _themeController.currentThemeColor, + borderRadius: BorderRadius.circular(2), + ), ), - ), const SizedBox(width: 12), Expanded( child: Column( diff --git a/lib/views/profile/guide/sp-guide.dart b/lib/views/profile/guide/sp-guide.dart index a0416d1..e12ea22 100644 --- a/lib/views/profile/guide/sp-guide.dart +++ b/lib/views/profile/guide/sp-guide.dart @@ -38,7 +38,7 @@ class _SpGuidePageState extends State final int _totalPages = 3; - final List _pageTitles = ['欢迎使用', '双击中心区域查看协议', '了解软件功能']; + final List _pageTitles = ['欢迎使用', '双击中心区域可左右滑动查看', '了解软件功能']; @override void initState() { @@ -191,7 +191,7 @@ class _SpGuidePageState extends State _nextPage(); }, style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: _themeController.currentThemeColor, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), @@ -221,6 +221,7 @@ class _SpGuidePageState extends State Widget build(BuildContext context) { return Obx(() { final isDark = _themeController.isDarkMode; + final primaryColor = _themeController.currentThemeColor; return WillPopScope( onWillPop: () async { if (widget.fromSettings) { @@ -230,7 +231,7 @@ class _SpGuidePageState extends State }, child: Scaffold( backgroundColor: isDark ? const Color(0xFF1A1A1A) : Colors.white, - appBar: _buildAppBar(isDark), + appBar: _buildAppBar(isDark, primaryColor), body: Stack( children: [ PageView( @@ -243,13 +244,13 @@ class _SpGuidePageState extends State }); }, children: [ - _buildWelcomePage(isDark), - _buildPrivacyPage(isDark), - _buildFeaturePage(isDark), + _buildWelcomePage(isDark, primaryColor), + _buildPrivacyPage(isDark, primaryColor), + _buildFeaturePage(isDark, primaryColor), ], ), - _buildPageIndicator(isDark), - _buildBottomNavigation(isDark), + _buildPageIndicator(isDark, primaryColor), + _buildBottomNavigation(isDark, primaryColor), ], ), ), @@ -257,7 +258,7 @@ class _SpGuidePageState extends State }); } - Widget _buildPageIndicator(bool isDark) { + Widget _buildPageIndicator(bool isDark, Color primaryColor) { double alignmentY; switch (_currentPage) { case 0: @@ -318,19 +319,17 @@ class _SpGuidePageState extends State decoration: BoxDecoration( shape: BoxShape.circle, color: isActive - ? AppConstants.primaryColor + ? primaryColor : isCompleted - ? AppConstants.primaryColor.withValues(alpha: 0.5) + ? primaryColor.withAlpha(50) : (isDark ? Colors.grey[600] : Colors.grey[300]), border: isActive - ? Border.all(color: AppConstants.primaryColor, width: 3) + ? Border.all(color: primaryColor, width: 3) : null, boxShadow: isActive ? [ BoxShadow( - color: AppConstants.primaryColor.withValues( - alpha: 0.3, - ), + color: primaryColor.withAlpha(30), blurRadius: 8, spreadRadius: 2, ), @@ -346,21 +345,18 @@ class _SpGuidePageState extends State ); } - PreferredSizeWidget _buildAppBar(bool isDark) { + PreferredSizeWidget _buildAppBar(bool isDark, Color primaryColor) { return AppBar( title: Text( _pageTitles[_currentPage], - style: TextStyle( - color: AppConstants.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold), ), backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, elevation: 0, centerTitle: true, leading: widget.fromSettings ? IconButton( - icon: Icon(Icons.arrow_back, color: AppConstants.primaryColor), + icon: Icon(Icons.arrow_back, color: primaryColor), onPressed: () => Navigator.pop(context), ) : null, @@ -368,7 +364,7 @@ class _SpGuidePageState extends State ); } - Widget _buildWelcomePage(bool isDark) { + Widget _buildWelcomePage(bool isDark, Color primaryColor) { return Container( padding: const EdgeInsets.all(32), child: Column( @@ -379,10 +375,7 @@ class _SpGuidePageState extends State height: 120, decoration: BoxDecoration( gradient: LinearGradient( - colors: [ - AppConstants.primaryColor.withValues(alpha: 0.1), - AppConstants.primaryColor.withValues(alpha: 0.05), - ], + colors: [primaryColor.withAlpha(10), primaryColor.withAlpha(5)], ), borderRadius: BorderRadius.circular(30), ), @@ -405,7 +398,7 @@ class _SpGuidePageState extends State style: TextStyle( fontSize: 24, fontWeight: FontWeight.w600, - color: AppConstants.primaryColor, + color: primaryColor, ), ), const SizedBox(height: 32), @@ -455,17 +448,10 @@ class _SpGuidePageState extends State ), ); }, - icon: Icon( - Icons.security, - size: 18, - color: AppConstants.primaryColor, - ), + icon: Icon(Icons.security, size: 18, color: primaryColor), label: Text( '了解软件权限', - style: TextStyle( - color: AppConstants.primaryColor, - fontSize: 14, - ), + style: TextStyle(color: primaryColor, fontSize: 14), ), style: TextButton.styleFrom( padding: const EdgeInsets.symmetric( @@ -474,9 +460,7 @@ class _SpGuidePageState extends State ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), - side: BorderSide( - color: AppConstants.primaryColor.withValues(alpha: 0.3), - ), + side: BorderSide(color: primaryColor.withAlpha(30)), ), ), ), @@ -536,7 +520,7 @@ class _SpGuidePageState extends State ? Icons.check_circle : Icons.info_outline, color: _showGuideOnStartup - ? AppConstants.primaryColor + ? _themeController.currentThemeColor : (isDark ? Colors.grey[400] : Colors.grey[600]), size: 24, ), @@ -556,7 +540,7 @@ class _SpGuidePageState extends State padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: _showGuideOnStartup - ? AppConstants.primaryColor.withValues(alpha: 0.1) + ? _themeController.currentThemeColor.withAlpha(10) : (isDark ? const Color(0xFF2A2A2A) : Colors.grey[50]), borderRadius: BorderRadius.circular(12), ), @@ -567,7 +551,7 @@ class _SpGuidePageState extends State ? Icons.notifications_active : Icons.notifications_off, color: _showGuideOnStartup - ? AppConstants.primaryColor + ? _themeController.currentThemeColor : (isDark ? Colors.grey[400] : Colors.grey[500]), size: 40, ), @@ -578,7 +562,7 @@ class _SpGuidePageState extends State fontSize: 16, fontWeight: FontWeight.w600, color: _showGuideOnStartup - ? AppConstants.primaryColor + ? _themeController.currentThemeColor : (isDark ? Colors.white : Colors.grey[700]), ), ), @@ -600,7 +584,7 @@ class _SpGuidePageState extends State child: ElevatedButton( onPressed: () => Navigator.pop(context), style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: _themeController.currentThemeColor, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( @@ -617,7 +601,7 @@ class _SpGuidePageState extends State ); } - Widget _buildPrivacyPage(bool isDark) { + Widget _buildPrivacyPage(bool isDark, Color primaryColor) { _initTabController(); return Stack( children: [ @@ -627,11 +611,11 @@ class _SpGuidePageState extends State color: isDark ? const Color(0xFF2A2A2A) : Colors.white, child: TabBar( controller: _tabController!, - labelColor: AppConstants.primaryColor, + labelColor: primaryColor, unselectedLabelColor: isDark ? Colors.grey[400] : Colors.grey[600], - indicatorColor: AppConstants.primaryColor, + indicatorColor: primaryColor, indicatorWeight: 2, tabs: const [ Tab(text: '《隐私政策》'), @@ -713,20 +697,14 @@ class _SpGuidePageState extends State left: 0, top: 0, bottom: 0, - child: Container( - width: 3, - color: AppConstants.primaryColor, - ), + child: Container(width: 3, color: primaryColor), ), if (_isAgreementFocused) Positioned( right: 0, top: 0, bottom: 0, - child: Container( - width: 3, - color: AppConstants.primaryColor, - ), + child: Container(width: 3, color: primaryColor), ), ], ), @@ -779,7 +757,7 @@ class _SpGuidePageState extends State _rejectAgreement(); } }, - activeColor: AppConstants.primaryColor, + activeColor: primaryColor, ), Expanded( child: GestureDetector( @@ -795,7 +773,7 @@ class _SpGuidePageState extends State style: TextStyle( fontSize: 14, color: _agreementAccepted - ? AppConstants.primaryColor + ? primaryColor : (isDark ? Colors.grey[300] : Colors.grey[700]), @@ -814,7 +792,7 @@ class _SpGuidePageState extends State : _rejectAndExit, style: ElevatedButton.styleFrom( backgroundColor: _agreementAccepted - ? AppConstants.primaryColor + ? primaryColor : (isDark ? Colors.grey[700] : Colors.grey[600]), foregroundColor: Colors.white, disabledBackgroundColor: isDark @@ -843,7 +821,7 @@ class _SpGuidePageState extends State ); } - Widget _buildFeaturePage(bool isDark) { + Widget _buildFeaturePage(bool isDark, Color primaryColor) { return Padding( padding: const EdgeInsets.fromLTRB(24, 16, 24, 100), child: Column( @@ -920,11 +898,7 @@ class _SpGuidePageState extends State ), child: Row( children: [ - Icon( - Icons.volunteer_activism, - color: AppConstants.primaryColor, - size: 18, - ), + Icon(Icons.volunteer_activism, color: primaryColor, size: 18), const SizedBox(width: 8), Expanded( child: GestureDetector( @@ -963,7 +937,7 @@ class _SpGuidePageState extends State Switch( value: _userPlanJoined, onChanged: _toggleUserPlan, - activeThumbColor: AppConstants.primaryColor, + activeThumbColor: primaryColor, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, ), ], @@ -1044,7 +1018,7 @@ class _SpGuidePageState extends State child: ElevatedButton( onPressed: _finishGuide, style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: primaryColor, foregroundColor: Colors.white, padding: EdgeInsets.zero, shape: RoundedRectangleBorder( @@ -1127,7 +1101,7 @@ class _SpGuidePageState extends State ); } - Widget _buildBottomNavigation(bool isDark) { + Widget _buildBottomNavigation(bool isDark, Color primaryColor) { return Positioned( bottom: 0, left: 0, @@ -1143,6 +1117,7 @@ class _SpGuidePageState extends State label: '上一页', onPressed: _previousPage, isDark: isDark, + primaryColor: primaryColor, ) : const SizedBox(width: 100), _currentPage < _totalPages - 1 @@ -1153,12 +1128,14 @@ class _SpGuidePageState extends State ? null : _nextPage, isDark: isDark, + primaryColor: primaryColor, ) : _buildNavButton( icon: Icons.check, label: '完成', onPressed: _agreementAccepted ? _finishGuide : null, isDark: isDark, + primaryColor: primaryColor, ), ], ), @@ -1171,17 +1148,18 @@ class _SpGuidePageState extends State required String label, VoidCallback? onPressed, required bool isDark, + required Color primaryColor, }) { return Container( decoration: BoxDecoration( color: onPressed != null - ? AppConstants.primaryColor + ? primaryColor : (isDark ? Colors.grey[700] : Colors.grey[300]), borderRadius: BorderRadius.circular(12), boxShadow: onPressed != null ? [ BoxShadow( - color: AppConstants.primaryColor.withValues(alpha: 0.3), + color: primaryColor.withAlpha(30), blurRadius: 8, offset: const Offset(0, 2), ), diff --git a/lib/views/profile/history_page.dart b/lib/views/profile/history_page.dart index 212d8af..dac85c1 100644 --- a/lib/views/profile/history_page.dart +++ b/lib/views/profile/history_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import '../../constants/app_constants.dart'; +import '../../models/colors/theme_colors.dart'; import '../../services/get/history_controller.dart'; import '../../services/get/theme_controller.dart'; @@ -16,11 +17,12 @@ class HistoryPage extends StatelessWidget { return Obx(() { final isDark = themeController.isDarkMode; + final primaryColor = themeController.currentThemeColor; return Scaffold( backgroundColor: isDark ? const Color(0xFF1A1A1A) : const Color(0xFFF2F2F7), - appBar: _buildAppBar(controller, isDark), + appBar: _buildAppBar(controller, isDark, primaryColor), body: Column( children: [ _buildSearchBar(controller, isDark), @@ -32,22 +34,26 @@ class HistoryPage extends StatelessWidget { ? _buildLoadingWidget(isDark) : controller.filteredHistoryList.isEmpty ? _buildEmptyWidget(isDark) - : _buildHistoryList(controller, isDark), + : _buildHistoryList(controller, isDark, primaryColor), ), ), - _buildPagination(controller, isDark), + _buildPagination(controller, isDark, primaryColor), ], ), ); }); } - PreferredSizeWidget _buildAppBar(HistoryController controller, bool isDark) { + PreferredSizeWidget _buildAppBar( + HistoryController controller, + bool isDark, + Color primaryColor, + ) { return AppBar( title: Text( '历史记录', style: TextStyle( - color: AppConstants.primaryColor, + color: primaryColor, fontWeight: FontWeight.w600, fontSize: 17, ), @@ -96,18 +102,12 @@ class HistoryPage extends StatelessWidget { CupertinoButton( padding: const EdgeInsets.symmetric(horizontal: 8), onPressed: controller.showStatsDialog, - child: const Icon( - CupertinoIcons.chart_bar, - color: AppConstants.primaryColor, - ), + child: Icon(CupertinoIcons.chart_bar, color: primaryColor), ), CupertinoButton( padding: const EdgeInsets.symmetric(horizontal: 8), onPressed: controller.exportHistory, - child: const Icon( - CupertinoIcons.share, - color: AppConstants.primaryColor, - ), + child: Icon(CupertinoIcons.share, color: primaryColor), ), ], ); @@ -361,7 +361,11 @@ class HistoryPage extends StatelessWidget { ); } - Widget _buildHistoryList(HistoryController controller, bool isDark) { + Widget _buildHistoryList( + HistoryController controller, + bool isDark, + Color primaryColor, + ) { final currentPageData = controller.getCurrentPageData(); return ListView.separated( @@ -380,6 +384,7 @@ class HistoryPage extends StatelessWidget { item, actualIndex, isDark, + primaryColor, ); }, ); @@ -391,6 +396,7 @@ class HistoryPage extends StatelessWidget { Map item, int actualIndex, bool isDark, + Color primaryColor, ) { return Container( decoration: BoxDecoration( @@ -412,7 +418,7 @@ class HistoryPage extends StatelessWidget { width: 44, height: 44, decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: primaryColor.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(22), ), child: Center( @@ -420,7 +426,7 @@ class HistoryPage extends StatelessWidget { '${actualIndex + 1}', style: TextStyle( fontSize: 16, - color: AppConstants.primaryColor, + color: primaryColor, fontWeight: FontWeight.w600, ), ), @@ -526,7 +532,11 @@ class HistoryPage extends StatelessWidget { ); } - Widget _buildPagination(HistoryController controller, bool isDark) { + Widget _buildPagination( + HistoryController controller, + bool isDark, + Color primaryColor, + ) { return Obx( () => Visibility( visible: controller.totalPages.value > 1, @@ -555,7 +565,7 @@ class HistoryPage extends StatelessWidget { vertical: 8, ), color: controller.currentPage.value > 1 - ? AppConstants.primaryColor + ? primaryColor : (isDark ? Colors.grey[800] : CupertinoColors.systemGrey5), borderRadius: BorderRadius.circular(8), child: Row( @@ -602,7 +612,7 @@ class HistoryPage extends StatelessWidget { ), color: controller.currentPage.value < controller.totalPages.value - ? AppConstants.primaryColor + ? primaryColor : (isDark ? Colors.grey[800] : CupertinoColors.systemGrey5), borderRadius: BorderRadius.circular(8), child: Row( diff --git a/lib/views/profile/level/distinguish.dart b/lib/views/profile/level/distinguish.dart index c9676f4..70c09be 100644 --- a/lib/views/profile/level/distinguish.dart +++ b/lib/views/profile/level/distinguish.dart @@ -1,3 +1,8 @@ +/// 时间: 2026-03-28 +/// 功能: 答题记录页面 +/// 介绍: 显示用户的诗词答题记录列表,包括题目、标签、是否答对等信息 +/// 最新变化: 添加统计数据弹窗功能,支持主题色设置 + import 'dart:convert'; import 'package:flutter/material.dart'; @@ -5,17 +10,12 @@ import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:intl/intl.dart'; -import '../../../constants/app_constants.dart'; +import '../../../models/colors/app_colors.dart'; import '../../../controllers/shared_preferences_storage_controller.dart'; import '../../../controllers/history_controller.dart'; import '../../../services/network_listener_service.dart'; import '../../../services/get/theme_controller.dart'; -/// 时间: 2026-03-28 -/// 功能: 答题记录页面 -/// 介绍: 显示用户的诗词答题记录列表,包括题目、标签、是否答对等信息 -/// 最新变化: 添加统计数据弹窗功能 - class DistinguishPage extends StatefulWidget { const DistinguishPage({super.key}); @@ -142,239 +142,234 @@ class _DistinguishPageState extends State { } void _showStatisticsDialog() { - final isDark = _themeController.isDarkMode; showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, - builder: (context) => _buildStatisticsSheet(isDark), + builder: (context) => _buildStatisticsSheet(), ); } - Widget _buildStatisticsSheet(bool isDark) { - return Container( - decoration: BoxDecoration( - color: isDark ? const Color(0xFF2A2A2A) : Colors.white, - borderRadius: const BorderRadius.vertical(top: Radius.circular(24)), - ), - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.all(24), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Center( - child: Container( - width: 40, - height: 4, - decoration: BoxDecoration( - color: isDark ? Colors.grey[600] : Colors.grey[300], - borderRadius: BorderRadius.circular(2), + Widget _buildStatisticsSheet() { + return Obx(() { + final isDark = _themeController.isDarkMode; + return Container( + decoration: BoxDecoration( + color: AppColors.surface, + borderRadius: const BorderRadius.vertical(top: Radius.circular(24)), + ), + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Container( + width: 40, + height: 4, + decoration: BoxDecoration( + color: AppColors.divider, + borderRadius: BorderRadius.circular(2), + ), ), ), - ), - const SizedBox(height: 20), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Container( - padding: const EdgeInsets.all(8), - decoration: BoxDecoration( - color: AppConstants.primaryColor.withAlpha(20), - borderRadius: BorderRadius.circular(10), + const SizedBox(height: 20), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: AppColors.primary.withAlpha(20), + borderRadius: BorderRadius.circular(10), + ), + child: Icon( + Icons.analytics_outlined, + color: AppColors.primary, + size: 24, + ), ), - child: Icon( - Icons.analytics_outlined, - color: AppConstants.primaryColor, - size: 24, - ), - ), - const SizedBox(width: 12), - Text( - '本次答题记录', - style: TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - color: isDark ? Colors.white : Colors.black87, - ), - ), - ], - ), - if (_answerRecords.isNotEmpty) - Container( - decoration: BoxDecoration( - color: AppConstants.primaryColor.withAlpha(15), - borderRadius: BorderRadius.circular(8), - border: Border.all( - color: AppConstants.primaryColor.withAlpha(50), - width: 0.5, - ), - ), - child: TextButton.icon( - onPressed: _copyStatisticsContent, - icon: Icon( - Icons.copy, - size: 16, - color: Colors.orange[700], - ), - label: Text( - '添加笔记', + const SizedBox(width: 12), + Text( + '本次答题记录', style: TextStyle( - fontSize: 12, + fontSize: 22, + fontWeight: FontWeight.bold, + color: AppColors.primaryText, + ), + ), + ], + ), + if (_answerRecords.isNotEmpty) + Container( + decoration: BoxDecoration( + color: AppColors.primary.withAlpha(15), + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: AppColors.primary.withAlpha(50), + width: 0.5, + ), + ), + child: TextButton.icon( + onPressed: _copyStatisticsContent, + icon: Icon( + Icons.copy, + size: 16, color: Colors.orange[700], ), - ), - style: TextButton.styleFrom( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 6, + label: Text( + '添加笔记', + style: TextStyle( + fontSize: 12, + color: Colors.orange[700], + ), + ), + style: TextButton.styleFrom( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 6, + ), + minimumSize: Size.zero, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), - minimumSize: Size.zero, - tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), ), - ), - ], - ), - const SizedBox(height: 24), - Container( - width: double.infinity, - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - AppConstants.primaryColor.withAlpha(10), - isDark ? const Color(0xFF2A2A2A) : Colors.white, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - borderRadius: BorderRadius.circular(16), - border: Border.all( - color: AppConstants.primaryColor.withAlpha(30), - width: 1, - ), - ), - child: Column( - children: [ - _buildStatRow('已答题', '$_totalQuestions 题', isDark), - _buildStatRow( - '正确', - '$_correctAnswers 题', - isDark, - isGreen: true, - ), - _buildStatRow( - '错误', - '$_wrongAnswers 题', - isDark, - isRed: true, - ), - _buildStatRow( - '正确率', - '${_correctRate.toStringAsFixed(1)}%', - isDark, - isGreen: _correctRate >= 60, - ), - _buildStatRow( - '错误率', - '${_wrongRate.toStringAsFixed(1)}%', - isDark, - isRed: _wrongRate > 40, - ), - _buildStatRow( - '平均用时', - '${_averageTime.toStringAsFixed(1)} 秒', - isDark, - ), - _buildStatRow('提示次数', '$_hintCount 次', isDark), - _buildStatRow('跳过次数', '$_skipCount 次', isDark), - Divider( - height: 24, - color: isDark ? Colors.grey[700] : Colors.grey[300], - ), - _buildStatRow( - '诗词水平', - _poetryLevel, - isDark, - isHighlight: true, - ), ], ), - ), - const SizedBox(height: 24), - SizedBox( - width: double.infinity, - child: Container( + const SizedBox(height: 24), + Container( + width: double.infinity, + padding: const EdgeInsets.all(20), decoration: BoxDecoration( gradient: LinearGradient( colors: [ - AppConstants.primaryColor, - AppConstants.primaryColor.withAlpha(200), + AppColors.primary.withAlpha(10), + AppColors.surface, ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: AppConstants.primaryColor.withAlpha(80), - blurRadius: 12, - offset: const Offset(0, 4), + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: AppColors.primary.withAlpha(30), + width: 1, + ), + ), + child: Column( + children: [ + _buildStatRow('已答题', '$_totalQuestions 题'), + _buildStatRow( + '正确', + '$_correctAnswers 题', + isGreen: true, + ), + _buildStatRow( + '错误', + '$_wrongAnswers 题', + isRed: true, + ), + _buildStatRow( + '正确率', + '${_correctRate.toStringAsFixed(1)}%', + isGreen: _correctRate >= 60, + ), + _buildStatRow( + '错误率', + '${_wrongRate.toStringAsFixed(1)}%', + isRed: _wrongRate > 40, + ), + _buildStatRow( + '平均用时', + '${_averageTime.toStringAsFixed(1)} 秒', + ), + _buildStatRow('提示次数', '$_hintCount 次'), + _buildStatRow('跳过次数', '$_skipCount 次'), + Divider( + height: 24, + color: AppColors.divider, + ), + _buildStatRow( + '诗词水平', + _poetryLevel, + isHighlight: true, ), ], ), - child: ElevatedButton( - onPressed: _copyStatisticsToClipboard, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.transparent, - shadowColor: Colors.transparent, - padding: const EdgeInsets.symmetric(vertical: 16), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), + ), + const SizedBox(height: 24), + SizedBox( + width: double.infinity, + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + AppColors.primary, + AppColors.primary.withAlpha(200), + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, ), - ), - child: const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.copy, color: Colors.white, size: 20), - SizedBox(width: 8), - Text( - '复制数据发送给AI评估', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: Colors.white, - ), + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: AppColors.primary.withAlpha(80), + blurRadius: 12, + offset: const Offset(0, 4), ), ], ), + child: ElevatedButton( + onPressed: _copyStatisticsToClipboard, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.transparent, + shadowColor: Colors.transparent, + padding: const EdgeInsets.symmetric(vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.copy, color: Colors.white, size: 20), + SizedBox(width: 8), + Text( + '复制数据发送给AI评估', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: Colors.white, + ), + ), + ], + ), + ), ), ), - ), - const SizedBox(height: 16), - ], + const SizedBox(height: 16), + ], + ), ), ), - ), - ); + ); + }); } Widget _buildStatRow( String label, - String value, - bool isDark, { + String value, { bool isGreen = false, bool isRed = false, bool isHighlight = false, }) { - Color valueColor = isDark ? Colors.white : Colors.black87; - if (isGreen) valueColor = Colors.green; - if (isRed) valueColor = Colors.red; - if (isHighlight) valueColor = AppConstants.primaryColor; + Color valueColor = AppColors.primaryText; + if (isGreen) valueColor = AppColors.iosGreen; + if (isRed) valueColor = AppColors.iosRed; + if (isHighlight) valueColor = AppColors.primary; return Padding( padding: const EdgeInsets.symmetric(vertical: 8), @@ -385,7 +380,7 @@ class _DistinguishPageState extends State { label, style: TextStyle( fontSize: 15, - color: isDark ? Colors.grey[400] : Colors.grey[700], + color: AppColors.secondaryText, ), ), Text( @@ -456,16 +451,17 @@ $_poetryLevel final confirmed = await showDialog( context: context, builder: (context) => AlertDialog( - title: const Text('确认清空'), - content: const Text('确定要清空所有答题记录吗?此操作不可恢复。'), + backgroundColor: AppColors.surface, + title: Text('确认清空', style: TextStyle(color: AppColors.primaryText)), + content: Text('确定要清空所有答题记录吗?此操作不可恢复。', style: TextStyle(color: AppColors.secondaryText)), actions: [ TextButton( onPressed: () => Navigator.pop(context, false), - child: const Text('取消'), + child: Text('取消', style: TextStyle(color: AppColors.primary)), ), TextButton( onPressed: () => Navigator.pop(context, true), - child: const Text('确定', style: TextStyle(color: Colors.red)), + child: Text('确定', style: TextStyle(color: AppColors.iosRed)), ), ], ), @@ -511,18 +507,18 @@ $_poetryLevel style: TextStyle( fontWeight: FontWeight.bold, fontSize: 20, - color: isDark ? Colors.white : Colors.white, + color: Colors.white, ), ), - backgroundColor: AppConstants.primaryColor, + backgroundColor: AppColors.primary, foregroundColor: Colors.white, elevation: 0, flexibleSpace: Container( decoration: BoxDecoration( gradient: LinearGradient( colors: [ - AppConstants.primaryColor, - AppConstants.primaryColor.withAlpha(180), + AppColors.primary, + AppColors.primary.withAlpha(180), ], begin: Alignment.topLeft, end: Alignment.bottomRight, @@ -544,239 +540,246 @@ $_poetryLevel ], ), body: Container( - color: isDark ? const Color(0xFF1A1A1A) : Colors.grey[50], + color: AppColors.background, child: SafeArea( child: _isLoading ? const Center(child: CircularProgressIndicator()) : _answerRecords.isEmpty - ? _buildEmptyView(isDark) - : _buildRecordList(isDark), + ? _buildEmptyView() + : _buildRecordList(), ), ), ); }); } - Widget _buildEmptyView(bool isDark) { - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.menu_book_outlined, - size: 80, - color: isDark ? Colors.grey[600] : Colors.grey[300], - ), - const SizedBox(height: 16), - Text( - '暂无答题记录', - style: TextStyle( - fontSize: 18, - color: isDark ? Colors.grey[400] : Colors.grey[500], - fontWeight: FontWeight.w500, + Widget _buildEmptyView() { + return Obx(() { + final isDark = _themeController.isDarkMode; + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.menu_book_outlined, + size: 80, + color: AppColors.tertiaryText, ), - ), - const SizedBox(height: 8), - Text( - '快去答题吧!', - style: TextStyle( - fontSize: 14, - color: isDark ? Colors.grey[500] : Colors.grey[400], + const SizedBox(height: 16), + Text( + '暂无答题记录', + style: TextStyle( + fontSize: 18, + color: AppColors.secondaryText, + fontWeight: FontWeight.w500, + ), ), - ), - ], - ), - ); + const SizedBox(height: 8), + Text( + '快去答题吧!', + style: TextStyle( + fontSize: 14, + color: AppColors.tertiaryText, + ), + ), + ], + ), + ); + }); } - Widget _buildRecordList(bool isDark) { - return ListView.builder( - padding: const EdgeInsets.all(16), - itemCount: _answerRecords.length, - itemBuilder: (context, index) { - final record = _answerRecords[index]; - return _buildRecordCard(record, index, isDark); - }, - ); + Widget _buildRecordList() { + return Obx(() { + final isDark = _themeController.isDarkMode; + return ListView.builder( + padding: const EdgeInsets.all(16), + itemCount: _answerRecords.length, + itemBuilder: (context, index) { + final record = _answerRecords[index]; + return _buildRecordCard(record, index); + }, + ); + }); } - Widget _buildRecordCard(Map record, int index, bool isDark) { + Widget _buildRecordCard(Map record, int index) { final question = record['question'] ?? '未知题目'; final author = record['author'] ?? '未知作者'; final tags = (record['tags'] as List?)?.cast() ?? []; final isCorrect = record['isCorrect'] ?? false; final answerTime = _formatTime(record['answerTime']); - return Container( - margin: const EdgeInsets.only(bottom: 12), - decoration: BoxDecoration( - color: isDark ? const Color(0xFF2A2A2A) : Colors.white, - borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: isDark - ? Colors.black.withAlpha(30) - : Colors.black.withAlpha(10), - blurRadius: 8, - offset: const Offset(0, 2), - ), - ], - ), - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 28, - height: 28, - decoration: BoxDecoration( - color: AppConstants.primaryColor.withAlpha(20), - borderRadius: BorderRadius.circular(8), - ), - child: Center( - child: Text( - '${index + 1}', - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: AppConstants.primaryColor, - ), - ), - ), - ), - const SizedBox(width: 12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - question, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - color: isDark ? Colors.white : Colors.black87, - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 4), - Text( - '—— $author', - style: TextStyle( - fontSize: 12, - color: isDark ? Colors.grey[400] : Colors.grey[600], - fontStyle: FontStyle.italic, - ), - ), - ], - ), - ), - const SizedBox(width: 8), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 10, - vertical: 4, - ), - decoration: BoxDecoration( - color: isCorrect - ? Colors.green.withAlpha(isDark ? 40 : 20) - : Colors.red.withAlpha(isDark ? 40 : 20), - borderRadius: BorderRadius.circular(12), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - isCorrect ? Icons.check_circle : Icons.cancel, - size: 14, - color: isCorrect ? Colors.green : Colors.red, - ), - const SizedBox(width: 4), - Text( - isCorrect ? '答对' : '答错', - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: isCorrect ? Colors.green : Colors.red, - ), - ), - ], - ), - ), - ], - ), - const SizedBox(height: 12), - Row( - children: [ - Expanded( - child: tags.isNotEmpty - ? Wrap( - spacing: 6, - runSpacing: 6, - children: tags.map((tag) { - return Container( - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 3, - ), - decoration: BoxDecoration( - color: AppConstants.primaryColor.withAlpha(15), - borderRadius: BorderRadius.circular(6), - border: Border.all( - color: AppConstants.primaryColor.withAlpha( - 50, - ), - width: 0.5, - ), - ), - child: Text( - tag, - style: TextStyle( - fontSize: 11, - color: AppConstants.primaryColor, - fontWeight: FontWeight.w500, - ), - ), - ); - }).toList(), - ) - : Text( - '暂无标签', - style: TextStyle( - fontSize: 12, - color: isDark ? Colors.grey[500] : Colors.grey[400], - fontStyle: FontStyle.italic, - ), - ), - ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Icons.access_time, - size: 12, - color: isDark ? Colors.grey[500] : Colors.grey[400], - ), - const SizedBox(width: 4), - Text( - answerTime, - style: TextStyle( - fontSize: 12, - color: isDark ? Colors.grey[400] : Colors.grey[500], - ), - ), - ], - ), - ], + return Obx(() { + final isDark = _themeController.isDarkMode; + return Container( + margin: const EdgeInsets.only(bottom: 12), + decoration: BoxDecoration( + color: AppColors.surface, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + color: Colors.black.withAlpha(isDark ? 30 : 10), + blurRadius: 8, + offset: const Offset(0, 2), ), ], ), - ), - ); + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: 28, + height: 28, + decoration: BoxDecoration( + color: AppColors.primary.withAlpha(20), + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: Text( + '${index + 1}', + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.bold, + color: AppColors.primary, + ), + ), + ), + ), + const SizedBox(width: 12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + question, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + color: AppColors.primaryText, + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 4), + Text( + '—— $author', + style: TextStyle( + fontSize: 12, + color: AppColors.secondaryText, + fontStyle: FontStyle.italic, + ), + ), + ], + ), + ), + const SizedBox(width: 8), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 4, + ), + decoration: BoxDecoration( + color: isCorrect + ? AppColors.iosGreen.withAlpha(20) + : AppColors.iosRed.withAlpha(20), + borderRadius: BorderRadius.circular(12), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + isCorrect ? Icons.check_circle : Icons.cancel, + size: 14, + color: isCorrect ? AppColors.iosGreen : AppColors.iosRed, + ), + const SizedBox(width: 4), + Text( + isCorrect ? '答对' : '答错', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: isCorrect ? AppColors.iosGreen : AppColors.iosRed, + ), + ), + ], + ), + ), + ], + ), + const SizedBox(height: 12), + Row( + children: [ + Expanded( + child: tags.isNotEmpty + ? Wrap( + spacing: 6, + runSpacing: 6, + children: tags.map((tag) { + return Container( + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 3, + ), + decoration: BoxDecoration( + color: AppColors.primary.withAlpha(15), + borderRadius: BorderRadius.circular(6), + border: Border.all( + color: AppColors.primary.withAlpha( + 50, + ), + width: 0.5, + ), + ), + child: Text( + tag, + style: TextStyle( + fontSize: 11, + color: AppColors.primary, + fontWeight: FontWeight.w500, + ), + ), + ); + }).toList(), + ) + : Text( + '暂无标签', + style: TextStyle( + fontSize: 12, + color: AppColors.tertiaryText, + fontStyle: FontStyle.italic, + ), + ), + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.access_time, + size: 12, + color: AppColors.tertiaryText, + ), + const SizedBox(width: 4), + Text( + answerTime, + style: TextStyle( + fontSize: 12, + color: AppColors.secondaryText, + ), + ), + ], + ), + ], + ), + ], + ), + ), + ); + }); } // 写入统计数据到笔记 diff --git a/lib/views/profile/level/flow-anim.dart b/lib/views/profile/level/flow-anim.dart index c1b7a1f..56398f9 100644 --- a/lib/views/profile/level/flow-anim.dart +++ b/lib/views/profile/level/flow-anim.dart @@ -1,8 +1,9 @@ import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:get/get.dart'; -import '../../../constants/app_constants.dart'; +import '../../../services/get/theme_controller.dart'; /// 流动边框装饰器 class FlowingBorderDecoration extends Decoration { @@ -61,7 +62,7 @@ class _FlowingBorderPainter extends BoxPainter { class FlowingBorderContainer extends StatefulWidget { final Widget child; final Duration duration; - final Color color; + final Color? color; final double width; final bool autoStart; @@ -69,7 +70,7 @@ class FlowingBorderContainer extends StatefulWidget { super.key, required this.child, this.duration = const Duration(seconds: 10), - this.color = AppConstants.primaryColor, + this.color, this.width = 4.0, this.autoStart = true, }); @@ -82,6 +83,7 @@ class _FlowingBorderContainerState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _animation; + final ThemeController _themeController = Get.find(); @override void initState() { @@ -105,19 +107,22 @@ class _FlowingBorderContainerState extends State @override Widget build(BuildContext context) { - return AnimatedBuilder( - animation: _animation, - builder: (context, child) { - return Container( - padding: EdgeInsets.all(widget.width), - decoration: FlowingBorderDecoration( - animation: _animation, - color: widget.color, - width: widget.width, - ), - child: widget.child, - ); - }, - ); + return Obx(() { + final color = widget.color ?? _themeController.currentThemeColor; + return AnimatedBuilder( + animation: _animation, + builder: (context, child) { + return Container( + padding: EdgeInsets.all(widget.width), + decoration: FlowingBorderDecoration( + animation: _animation, + color: color, + width: widget.width, + ), + child: widget.child, + ); + }, + ); + }); } } diff --git a/lib/views/profile/level/poetry.dart b/lib/views/profile/level/poetry.dart index 4f374e0..74ff29e 100644 --- a/lib/views/profile/level/poetry.dart +++ b/lib/views/profile/level/poetry.dart @@ -1,10 +1,15 @@ +/// 时间: 2026-03-28 +/// 功能: 诗词答题页面 +/// 介绍: 基于 API 接口实现的诗词答题系统,支持获取题目、提交答案、获取提示 +/// 最新变化: 添加自动加载下一题开关,隐藏提示标签,使用独立逻辑管理器,支持主题色设置 + import 'dart:async'; import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import '../../../constants/app_constants.dart'; +import '../../../models/colors/app_colors.dart'; import '../../../controllers/shared_preferences_storage_controller.dart'; import '../../../services/get/theme_controller.dart'; import '../guide/tongji.dart'; @@ -13,11 +18,6 @@ import 'flow-anim.dart'; import 'distinguish.dart'; import '../settings/offline-data.dart'; -/// 时间: 2026-03-28 -/// 功能: 诗词答题页面 -/// 介绍: 基于 API 接口实现的诗词答题系统,支持获取题目、提交答案、获取提示 -/// 最新变化: 添加自动加载下一题开关,隐藏提示标签,使用独立逻辑管理器 - class PoetryLevelPage extends StatefulWidget { const PoetryLevelPage({super.key}); @@ -137,7 +137,7 @@ class _PoetryLevelPageState extends State ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(initResult.message ?? '已加载离线缓存'), - backgroundColor: AppConstants.primaryColor, + backgroundColor: AppColors.primary, duration: const Duration(seconds: 2), ), ); @@ -153,14 +153,15 @@ class _PoetryLevelPageState extends State context: context, builder: (BuildContext context) { return AlertDialog( - title: const Text('提示'), - content: const Text('当前无网络连接且无离线缓存数据,请先下载数据或检查网络设置。'), + backgroundColor: AppColors.surface, + title: Text('提示', style: TextStyle(color: AppColors.primaryText)), + content: Text('当前无网络连接且无离线缓存数据,请先下载数据或检查网络设置。', style: TextStyle(color: AppColors.secondaryText)), actions: [ TextButton( onPressed: () { Navigator.of(context).pop(); }, - child: const Text('取消'), + child: Text('取消', style: TextStyle(color: AppColors.primary)), ), TextButton( onPressed: () { @@ -171,7 +172,7 @@ class _PoetryLevelPageState extends State MaterialPageRoute(builder: (_) => const OfflineDataPage()), ); }, - child: const Text('去下载'), + child: Text('去下载', style: TextStyle(color: AppColors.primary)), ), ], ); @@ -464,7 +465,7 @@ class _PoetryLevelPageState extends State return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( - color: AppConstants.primaryColor.withAlpha(20), + color: AppColors.primary.withAlpha(20), borderRadius: BorderRadius.circular(4), ), child: Column( @@ -474,7 +475,7 @@ class _PoetryLevelPageState extends State label, style: TextStyle( fontSize: 10, - color: AppConstants.primaryColor, + color: AppColors.primary, fontWeight: FontWeight.w600, ), ), @@ -482,7 +483,7 @@ class _PoetryLevelPageState extends State value, style: TextStyle( fontSize: 12, - color: Colors.black87, + color: AppColors.primaryText, fontWeight: FontWeight.w500, ), ), @@ -500,150 +501,152 @@ class _PoetryLevelPageState extends State final isWrong = _showFeedback && !_isAnswerCorrect && _selectedAnswer == optionNum; - return AnimatedContainer( - duration: const Duration(milliseconds: 300), - child: Container( - decoration: BoxDecoration( - gradient: isSelected - ? LinearGradient( - colors: isCorrect - ? [Colors.green[400]!, Colors.green[300]!] - : isWrong - ? [Colors.red[400]!, Colors.red[300]!] - : [ - AppConstants.primaryColor, - AppConstants.primaryColor.withAlpha(200), - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ) - : null, - color: isSelected ? null : Colors.white, - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: isSelected - ? Colors.transparent - : AppConstants.primaryColor.withAlpha(50), - width: 2, - ), - boxShadow: isSelected - ? [ - BoxShadow( - color: - (isCorrect - ? Colors.green - : isWrong - ? Colors.red - : AppConstants.primaryColor) - .withAlpha(80), - blurRadius: 12, - offset: const Offset(0, 4), - ), - ] - : [ - BoxShadow( - color: Colors.black.withAlpha(5), - blurRadius: 8, - offset: const Offset(0, 2), - ), - ], - ), - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: _isSubmitting || (_showFeedback && _isAnswerCorrect) - ? null - : () { - if (_showFeedback) { - // 重置状态,允许重新选择 - setState(() { - _showFeedback = false; - _selectedAnswer = null; - _feedbackMessage = null; - }); - } - _submitAnswer(optionNum); - }, + return Obx(() { + final isDark = _themeController.isDarkMode; + return AnimatedContainer( + duration: const Duration(milliseconds: 300), + child: Container( + decoration: BoxDecoration( + gradient: isSelected + ? LinearGradient( + colors: isCorrect + ? [AppColors.iosGreen, AppColors.iosGreen.withAlpha(200)] + : isWrong + ? [AppColors.iosRed, AppColors.iosRed.withAlpha(200)] + : [ + AppColors.primary, + AppColors.primary.withAlpha(200), + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ) + : null, + color: isSelected ? null : AppColors.surface, borderRadius: BorderRadius.circular(12), - child: Padding( - padding: const EdgeInsets.all(16), - child: Row( - children: [ - AnimatedContainer( - duration: const Duration(milliseconds: 300), - width: 32, - height: 32, - decoration: BoxDecoration( - gradient: isSelected - ? LinearGradient( - colors: isCorrect - ? [Colors.white, Colors.white.withAlpha(230)] - : isWrong - ? [Colors.white, Colors.white.withAlpha(230)] - : [Colors.white, Colors.white.withAlpha(230)], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ) - : null, - color: isSelected - ? null - : AppConstants.primaryColor.withAlpha(20), - shape: BoxShape.circle, - boxShadow: isSelected - ? [ - BoxShadow( - color: Colors.black.withAlpha(20), - blurRadius: 4, - offset: const Offset(0, 2), - ), - ] - : null, + border: Border.all( + color: isSelected + ? Colors.transparent + : AppColors.primary.withAlpha(50), + width: 2, + ), + boxShadow: isSelected + ? [ + BoxShadow( + color: (isCorrect + ? AppColors.iosGreen + : isWrong + ? AppColors.iosRed + : AppColors.primary) + .withAlpha(80), + blurRadius: 12, + offset: const Offset(0, 4), ), - child: Center( - child: Text( - '$optionNum', - style: TextStyle( - color: isSelected - ? (isCorrect - ? Colors.green + ] + : [ + BoxShadow( + color: Colors.black.withAlpha(isDark ? 10 : 5), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: _isSubmitting || (_showFeedback && _isAnswerCorrect) + ? null + : () { + if (_showFeedback) { + // 重置状态,允许重新选择 + setState(() { + _showFeedback = false; + _selectedAnswer = null; + _feedbackMessage = null; + }); + } + _submitAnswer(optionNum); + }, + borderRadius: BorderRadius.circular(12), + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + children: [ + AnimatedContainer( + duration: const Duration(milliseconds: 300), + width: 32, + height: 32, + decoration: BoxDecoration( + gradient: isSelected + ? LinearGradient( + colors: isCorrect + ? [Colors.white, Colors.white.withAlpha(230)] : isWrong - ? Colors.red - : AppConstants.primaryColor) - : AppConstants.primaryColor, - fontWeight: FontWeight.bold, - fontSize: 16, + ? [Colors.white, Colors.white.withAlpha(230)] + : [Colors.white, Colors.white.withAlpha(230)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ) + : null, + color: isSelected + ? null + : AppColors.primary.withAlpha(20), + shape: BoxShape.circle, + boxShadow: isSelected + ? [ + BoxShadow( + color: Colors.black.withAlpha(20), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ] + : null, + ), + child: Center( + child: Text( + '$optionNum', + style: TextStyle( + color: isSelected + ? (isCorrect + ? AppColors.iosGreen + : isWrong + ? AppColors.iosRed + : AppColors.primary) + : AppColors.primary, + fontWeight: FontWeight.bold, + fontSize: 16, + ), ), ), ), - ), - const SizedBox(width: 16), - Expanded( - child: Text( - option['content'] ?? option['text'] ?? '', - style: TextStyle( - fontSize: 17, - fontWeight: FontWeight.w500, - color: isSelected ? Colors.white : Colors.black87, + const SizedBox(width: 16), + Expanded( + child: Text( + option['content'] ?? option['text'] ?? '', + style: TextStyle( + fontSize: 17, + fontWeight: FontWeight.w500, + color: isSelected ? Colors.white : AppColors.primaryText, + ), ), ), - ), - if (isSelected) - Icon( - isCorrect - ? Icons.check_circle - : isWrong - ? Icons.cancel - : Icons.radio_button_checked, - color: Colors.white, - size: 28, - ), - ], + if (isSelected) + Icon( + isCorrect + ? Icons.check_circle + : isWrong + ? Icons.cancel + : Icons.radio_button_checked, + color: Colors.white, + size: 28, + ), + ], + ), ), ), ), ), - ), - ); + ); + }); } @override @@ -660,15 +663,15 @@ class _PoetryLevelPageState extends State color: Colors.white, ), ), - backgroundColor: AppConstants.primaryColor, + backgroundColor: AppColors.primary, foregroundColor: Colors.white, elevation: 0, flexibleSpace: Container( decoration: BoxDecoration( gradient: LinearGradient( colors: [ - AppConstants.primaryColor, - AppConstants.primaryColor.withAlpha(180), + AppColors.primary, + AppColors.primary.withAlpha(180), ], begin: Alignment.topLeft, end: Alignment.bottomRight, @@ -707,7 +710,7 @@ class _PoetryLevelPageState extends State ], ), body: Container( - color: isDark ? const Color(0xFF1A1A1A) : Colors.white, + color: AppColors.background, child: SafeArea( child: Padding( padding: const EdgeInsets.only( @@ -737,8 +740,8 @@ class _PoetryLevelPageState extends State decoration: BoxDecoration( gradient: LinearGradient( colors: [ - AppConstants.primaryColor, - AppConstants.primaryColor.withAlpha(200), + AppColors.primary, + AppColors.primary.withAlpha(200), ], begin: Alignment.topLeft, end: Alignment.bottomRight, @@ -746,7 +749,7 @@ class _PoetryLevelPageState extends State borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( - color: AppConstants.primaryColor.withAlpha( + color: AppColors.primary.withAlpha( 80, ), blurRadius: 12, @@ -841,7 +844,7 @@ class _PoetryLevelPageState extends State children: [ CircularProgressIndicator( valueColor: AlwaysStoppedAnimation( - AppConstants.primaryColor, + AppColors.primary, ), strokeWidth: 3, ), @@ -850,9 +853,7 @@ class _PoetryLevelPageState extends State '加载题目中...', style: TextStyle( fontSize: 16, - color: isDark - ? Colors.grey[400] - : Colors.grey, + color: AppColors.tertiaryText, ), ), ], @@ -870,14 +871,14 @@ class _PoetryLevelPageState extends State padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: isDark - ? Colors.red[900]!.withAlpha(30) - : Colors.red[50], + ? AppColors.iosRed.withAlpha(30) + : AppColors.iosRed.withAlpha(10), shape: BoxShape.circle, ), child: Icon( Icons.error_outline, size: 64, - color: Colors.red[400], + color: AppColors.iosRed, ), ), const SizedBox(height: 24), @@ -886,9 +887,7 @@ class _PoetryLevelPageState extends State textAlign: TextAlign.center, style: TextStyle( fontSize: 16, - color: isDark - ? Colors.red[300] - : Colors.red, + color: AppColors.iosRed, ), ), const SizedBox(height: 32), @@ -896,8 +895,8 @@ class _PoetryLevelPageState extends State decoration: BoxDecoration( gradient: LinearGradient( colors: [ - AppConstants.primaryColor, - AppConstants.primaryColor.withAlpha( + AppColors.primary, + AppColors.primary.withAlpha( 200, ), ], @@ -905,7 +904,7 @@ class _PoetryLevelPageState extends State borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( - color: AppConstants.primaryColor + color: AppColors.primary .withAlpha(80), blurRadius: 8, offset: const Offset(0, 4), @@ -967,15 +966,9 @@ class _PoetryLevelPageState extends State BorderRadius.circular( 16, ), - color: isDark - ? const Color( - 0xFF2A2A2A, - ) - : Colors.white, + color: AppColors.surface, ), ), - color: AppConstants - .primaryColor, width: 4, ), ), @@ -986,19 +979,10 @@ class _PoetryLevelPageState extends State decoration: BoxDecoration( gradient: LinearGradient( colors: [ - isDark - ? const Color( - 0xFF2A2A2A, - ) - : Colors.white, - AppConstants - .primaryColor + AppColors.surface, + AppColors.primary .withAlpha(5), - isDark - ? const Color( - 0xFF2A2A2A, - ) - : Colors.white, + AppColors.surface, ], begin: Alignment.topLeft, end: @@ -1023,8 +1007,8 @@ class _PoetryLevelPageState extends State width: 4, height: 20, decoration: BoxDecoration( - color: AppConstants - .primaryColor, + color: AppColors + .primary, borderRadius: BorderRadius.circular( 2, @@ -1041,8 +1025,8 @@ class _PoetryLevelPageState extends State fontWeight: FontWeight .w600, - color: AppConstants - .primaryColor, + color: AppColors + .primary, ), ), ], @@ -1058,9 +1042,7 @@ class _PoetryLevelPageState extends State fontWeight: FontWeight.bold, height: 1.5, - color: isDark - ? Colors.white - : Colors.black87, + color: AppColors.primaryText, ), ), // 标签信息 @@ -1082,8 +1064,8 @@ class _PoetryLevelPageState extends State 12, ), decoration: BoxDecoration( - color: AppConstants - .primaryColor + color: AppColors + .primary .withAlpha( 10, ), @@ -1141,7 +1123,7 @@ class _PoetryLevelPageState extends State width: double.infinity, padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: Colors.white, + color: AppColors.surface, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( @@ -1162,8 +1144,8 @@ class _PoetryLevelPageState extends State decoration: BoxDecoration( gradient: LinearGradient( colors: [ - Colors.white, - Colors.grey[50]!, + AppColors.surface, + AppColors.background, ], begin: Alignment.topLeft, end: Alignment.bottomRight, @@ -1171,7 +1153,7 @@ class _PoetryLevelPageState extends State borderRadius: BorderRadius.circular(12), border: Border.all( - color: AppConstants.primaryColor + color: AppColors.primary .withAlpha(50), width: 1, ), @@ -1195,18 +1177,18 @@ class _PoetryLevelPageState extends State children: [ Icon( Icons.arrow_back, - color: AppConstants - .primaryColor, + color: AppColors + .primary, size: 20, ), const SizedBox(width: 8), - const Text( + Text( '上一题', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, - color: Colors.black87, + color: AppColors.primaryText, ), ), ], @@ -1221,24 +1203,20 @@ class _PoetryLevelPageState extends State decoration: BoxDecoration( gradient: LinearGradient( colors: [ - Colors.white, - Colors.grey[50]!, + AppColors.primary, + AppColors.primary.withAlpha( + 200, + ), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(12), - border: Border.all( - color: - AppConstants.primaryColor, - width: 2, - ), boxShadow: [ BoxShadow( - color: AppConstants - .primaryColor - .withAlpha(30), + color: AppColors.primary + .withAlpha(80), blurRadius: 8, offset: const Offset(0, 4), ), @@ -1247,8 +1225,7 @@ class _PoetryLevelPageState extends State child: ElevatedButton( onPressed: _getHint, style: ElevatedButton.styleFrom( - backgroundColor: - Colors.transparent, + backgroundColor: Colors.transparent, shadowColor: Colors.transparent, padding: const EdgeInsets.symmetric( @@ -1263,10 +1240,9 @@ class _PoetryLevelPageState extends State mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( + const Icon( Icons.lightbulb_outline, - color: AppConstants - .primaryColor, + color: Colors.white, size: 20, ), const SizedBox(width: 8), @@ -1275,8 +1251,8 @@ class _PoetryLevelPageState extends State style: TextStyle( fontSize: 14, fontWeight: - FontWeight.w600, - color: Colors.black87, + FontWeight.w500, + color: Colors.white, ), ), ], @@ -1291,31 +1267,24 @@ class _PoetryLevelPageState extends State decoration: BoxDecoration( gradient: LinearGradient( colors: [ - AppConstants.primaryColor, - AppConstants.primaryColor - .withAlpha(200), + AppColors.surface, + AppColors.background, ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(12), - boxShadow: [ - BoxShadow( - color: AppConstants - .primaryColor - .withAlpha(80), - blurRadius: 12, - offset: const Offset(0, 4), - ), - ], + border: Border.all( + color: AppColors.primary + .withAlpha(50), + width: 1, + ), ), - child: ElevatedButton( + child: OutlinedButton( onPressed: _nextQuestion, - style: ElevatedButton.styleFrom( - backgroundColor: - Colors.transparent, - shadowColor: Colors.transparent, + style: OutlinedButton.styleFrom( + side: BorderSide.none, padding: const EdgeInsets.symmetric( vertical: 14, @@ -1329,19 +1298,20 @@ class _PoetryLevelPageState extends State mainAxisAlignment: MainAxisAlignment.center, children: [ - const Text( + Text( '下一题', style: TextStyle( fontSize: 14, fontWeight: - FontWeight.w600, - color: Colors.white, + FontWeight.w500, + color: AppColors.primaryText, ), ), const SizedBox(width: 8), Icon( Icons.arrow_forward, - color: Colors.white, + color: AppColors + .primary, size: 20, ), ], @@ -1351,6 +1321,38 @@ class _PoetryLevelPageState extends State ), ], ), + if (_showFeedback && _feedbackMessage != null) + Padding( + padding: const EdgeInsets.only(top: 16), + child: Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: _isAnswerCorrect + ? AppColors.iosGreen + .withAlpha(20) + : AppColors.iosRed + .withAlpha(20), + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: _isAnswerCorrect + ? AppColors.iosGreen + : AppColors.iosRed, + width: 1, + ), + ), + child: Text( + _feedbackMessage!, + style: TextStyle( + color: _isAnswerCorrect + ? AppColors.iosGreen + : AppColors.iosRed, + fontSize: 14, + fontWeight: FontWeight.w500, + ), + textAlign: TextAlign.center, + ), + ), + ), ], ), ), @@ -1359,65 +1361,6 @@ class _PoetryLevelPageState extends State ), ], ), - // 反馈信息气泡(不占用布局) - if (_showFeedback && _feedbackMessage != null) - Positioned( - top: 0, - left: 16, - right: 16, - child: AnimatedContainer( - duration: const Duration(milliseconds: 500), - curve: Curves.easeOut, - transform: Matrix4.translationValues(0, 0, 0), - padding: const EdgeInsets.symmetric( - horizontal: 20, - vertical: 12, - ), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: _isAnswerCorrect - ? [Colors.green[400]!, Colors.green[300]!] - : [Colors.orange[400]!, Colors.orange[300]!], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - borderRadius: BorderRadius.circular(20), - boxShadow: [ - BoxShadow( - color: - (_isAnswerCorrect - ? Colors.green - : Colors.orange) - .withAlpha(80), - blurRadius: 12, - offset: const Offset(0, 4), - ), - ], - ), - child: Row( - children: [ - Icon( - _isAnswerCorrect - ? Icons.celebration - : Icons.lightbulb_outline, - color: Colors.white, - size: 24, - ), - const SizedBox(width: 12), - Expanded( - child: Text( - _feedbackMessage!, - style: const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: Colors.white, - ), - ), - ), - ], - ), - ), - ), ], ), ), diff --git a/lib/views/profile/per_card.dart b/lib/views/profile/per_card.dart index 2ad2a40..c93c42e 100644 --- a/lib/views/profile/per_card.dart +++ b/lib/views/profile/per_card.dart @@ -5,6 +5,8 @@ import 'package:flutter/services.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:get/get.dart'; import '../../constants/app_constants.dart'; +import '../../models/colors/theme_colors.dart'; +import '../../services/get/theme_controller.dart'; import '../../services/network_listener_service.dart'; import 'guide/tongji.dart'; @@ -43,6 +45,7 @@ class PersonalCardState extends State { bool _isUserPlanJoined = false; late TextEditingController _nicknameController; int _currentAvatarIndex = 0; + final ThemeController _themeController = Get.find(); // 累计数据 int _totalViews = 0; @@ -284,6 +287,7 @@ class PersonalCardState extends State { @override Widget build(BuildContext context) { + final primaryColor = _themeController.currentThemeColor; return Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( @@ -302,8 +306,8 @@ class PersonalCardState extends State { decoration: BoxDecoration( gradient: LinearGradient( colors: [ - AppConstants.primaryColor.withOpacity(0.95), - AppConstants.primaryColor.withOpacity(0.85), + primaryColor.withOpacity(0.95), + primaryColor.withOpacity(0.85), ], begin: Alignment.topLeft, end: Alignment.bottomRight, @@ -327,7 +331,7 @@ class PersonalCardState extends State { ), // 内容层 _isExpanded - ? _buildExpandedContent() + ? _buildExpandedContent(primaryColor) : _buildCollapsedContent(), ], ), @@ -453,7 +457,7 @@ class PersonalCardState extends State { ); } - Widget _buildExpandedContent() { + Widget _buildExpandedContent(Color primaryColor) { return Column( children: [ // 头部信息 @@ -520,18 +524,18 @@ class PersonalCardState extends State { child: _isEditingNickname ? TextField( controller: _nicknameController, - style: const TextStyle( - color: AppConstants.primaryColor, + style: TextStyle( + color: primaryColor, fontSize: 18, fontWeight: FontWeight.bold, ), - decoration: const InputDecoration( + decoration: InputDecoration( border: InputBorder.none, focusedBorder: InputBorder.none, enabledBorder: InputBorder.none, hintText: '输入昵称', hintStyle: TextStyle( - color: AppConstants.primaryColor, + color: primaryColor, fontSize: 18, fontWeight: FontWeight.bold, ), @@ -682,8 +686,8 @@ class PersonalCardState extends State { Expanded( child: Text( '💡 $_currentTip', - style: const TextStyle( - color: AppConstants.primaryColor, + style: TextStyle( + color: primaryColor, fontSize: 14, fontWeight: FontWeight.w600, height: 1.3, @@ -698,7 +702,7 @@ class PersonalCardState extends State { onChanged: (value) { _toggleOnlineStatus(); }, - activeColor: AppConstants.primaryColor, + activeColor: primaryColor, inactiveTrackColor: Colors.grey.shade300, inactiveThumbColor: Colors.grey, ), diff --git a/lib/views/profile/profile_page.dart b/lib/views/profile/profile_page.dart index 23ca504..2fa5d03 100644 --- a/lib/views/profile/profile_page.dart +++ b/lib/views/profile/profile_page.dart @@ -12,6 +12,7 @@ import 'package:get/get.dart'; import '../../constants/app_constants.dart'; import '../../config/app_config.dart'; +import '../../models/colors/theme_colors.dart'; import 'history_page.dart'; import 'per_card.dart'; import 'settings/app_fun.dart'; @@ -43,13 +44,14 @@ class ProfilePage extends StatelessWidget { return Obx(() { final isDark = themeController.isDarkMode; + final primaryColor = themeController.currentThemeColor; return GetBuilder( builder: (controller) { return Scaffold( backgroundColor: isDark ? const Color(0xFF1A1A1A) : const Color(0xFFF5F5F5), - appBar: _buildAppBar(controller, isDark), + appBar: _buildAppBar(controller, isDark, primaryColor), body: GestureDetector( behavior: HitTestBehavior.opaque, onVerticalDragStart: (details) { @@ -77,9 +79,9 @@ class ProfilePage extends StatelessWidget { controller: pageController, onPageChanged: controller.onPageChanged, children: [ - _buildPage1(controller, isDark), - _buildPage2(controller, isDark), - _buildPage3(controller, isDark), + _buildPage1(controller, isDark, primaryColor), + _buildPage2(controller, isDark, primaryColor), + _buildPage3(controller, isDark, primaryColor), ], ), ), @@ -92,21 +94,22 @@ class ProfilePage extends StatelessWidget { }); } - PreferredSizeWidget _buildAppBar(ProfileController controller, bool isDark) { + PreferredSizeWidget _buildAppBar( + ProfileController controller, + bool isDark, + Color primaryColor, + ) { return AppBar( title: Text( '个人', - style: TextStyle( - color: AppConstants.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold), ), backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, elevation: 0, centerTitle: true, actions: [ IconButton( - icon: Icon(Icons.more_horiz, color: AppConstants.primaryColor), + icon: Icon(Icons.more_horiz, color: primaryColor), onPressed: () => _showMoreOptions(controller), ), ], @@ -141,7 +144,11 @@ class ProfilePage extends StatelessWidget { ); } - Widget _buildPage1(ProfileController controller, bool isDark) { + Widget _buildPage1( + ProfileController controller, + bool isDark, + Color primaryColor, + ) { return SingleChildScrollView( // 添加底部内边距,让内容延伸到导航栏下方,实现玻璃效果 padding: EdgeInsets.only( @@ -175,14 +182,14 @@ class ProfilePage extends StatelessWidget { children: [ Icon( Icons.analytics_outlined, - color: AppConstants.primaryColor, + color: primaryColor, size: 20, ), const SizedBox(width: 8), Text( '诗词挑战', style: TextStyle( - color: AppConstants.primaryColor, + color: primaryColor, fontSize: 16, fontWeight: FontWeight.bold, ), @@ -199,16 +206,19 @@ class ProfilePage extends StatelessWidget { '今日答题', '${controller.todayQuestions.value}', isDark, + primaryColor, ), _buildInteractionItem( '本周答题', '${controller.weekQuestions.value}', isDark, + primaryColor, ), _buildInteractionItem( '答对次数', '${controller.correctAnswers.value}', isDark, + primaryColor, ), ], ); @@ -235,7 +245,7 @@ class ProfilePage extends StatelessWidget { Get.to(const PoetryLevelPage()); }, style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: primaryColor, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), @@ -272,16 +282,12 @@ class ProfilePage extends StatelessWidget { children: [ Row( children: [ - Icon( - Icons.person_outline, - color: AppConstants.primaryColor, - size: 20, - ), + Icon(Icons.person_outline, color: primaryColor, size: 20), const SizedBox(width: 8), Text( '统计', style: TextStyle( - color: AppConstants.primaryColor, + color: primaryColor, fontSize: 16, fontWeight: FontWeight.bold, ), @@ -350,7 +356,11 @@ class ProfilePage extends StatelessWidget { ); } - Widget _buildPage2(ProfileController controller, bool isDark) { + Widget _buildPage2( + ProfileController controller, + bool isDark, + Color primaryColor, + ) { return ListView( // 添加底部内边距,让内容延伸到导航栏下方,实现玻璃效果 padding: EdgeInsets.only( @@ -360,80 +370,109 @@ class ProfilePage extends StatelessWidget { bottom: AppConfig.liquidGlassTotalHeight + 16, ), children: [ - _buildSettingsGroup('软件设置', [ - _buildSettingsItem( - '功能设置', - Icons.verified_user, - () => Get.to(const AppFunSettingsPage()), - isDark, - ), - _buildSettingsItem( - '离线使用', - Icons.volunteer_activism, - () => Get.to(const OfflineDataPage()), - isDark, - ), - _buildSettingsItem( - '历史记录', - Icons.history, - () => Get.to(const HistoryPage()), - isDark, - ), - _buildSettingsItem( - '主题风格', - Icons.palette, - () => Get.to(const AppDiyPage()), - isDark, - ), - ], isDark), + _buildSettingsGroup( + '软件设置', + [ + _buildSettingsItem( + '功能设置', + Icons.verified_user, + () => Get.to(const AppFunSettingsPage()), + isDark, + primaryColor, + ), + _buildSettingsItem( + '离线使用', + Icons.volunteer_activism, + () => Get.to(const OfflineDataPage()), + isDark, + primaryColor, + ), + _buildSettingsItem( + '历史记录', + Icons.history, + () => Get.to(const HistoryPage()), + isDark, + primaryColor, + ), + _buildSettingsItem( + '主题风格', + Icons.palette, + () => Get.to(const AppDiyPage()), + isDark, + primaryColor, + ), + ], + isDark, + primaryColor, + ), const SizedBox(height: 16), - _buildSettingsGroup('隐私设置', [ - _buildSettingsItem( - '权限管理', - Icons.block, - () => Get.to(const PermissionPage()), - isDark, - ), - _buildSettingsItem( - '应用数据', - Icons.security, - () => Get.to(const AppDataPage()), - isDark, - ), - _buildSettingsItem( - '软件协议', - Icons.description, - () => Get.to(const PrivacyPage()), - isDark, - ), - ], isDark), + _buildSettingsGroup( + '隐私设置', + [ + _buildSettingsItem( + '权限管理', + Icons.block, + () => Get.to(const PermissionPage()), + isDark, + primaryColor, + ), + _buildSettingsItem( + '应用数据', + Icons.security, + () => Get.to(const AppDataPage()), + isDark, + primaryColor, + ), + _buildSettingsItem( + '软件协议', + Icons.description, + () => Get.to(const PrivacyPage()), + isDark, + primaryColor, + ), + ], + isDark, + primaryColor, + ), const SizedBox(height: 16), - _buildSettingsGroup('软件信息', [ - _buildSettingsItem( - '应用信息', - Icons.phone_android, - () => Get.to(const AppInfoPage()), - isDark, - ), - _buildSettingsItem( - '了解我们', - Icons.info, - () => Get.to(const LearnUsPage()), - isDark, - ), - _buildSettingsItem( - '已知bug', - Icons.cleaning_services, - () => showBugListBottomSheet(Get.context!), - isDark, - ), - _buildScreenWakeItem(controller, isDark), - ], isDark), + _buildSettingsGroup( + '软件信息', + [ + _buildSettingsItem( + '应用信息', + Icons.phone_android, + () => Get.to(const AppInfoPage()), + isDark, + primaryColor, + ), + _buildSettingsItem( + '了解我们', + Icons.info, + () => Get.to(const LearnUsPage()), + isDark, + primaryColor, + ), + _buildSettingsItem( + '已知bug', + Icons.cleaning_services, + () => showBugListBottomSheet(Get.context!), + isDark, + primaryColor, + ), + _buildScreenWakeItem(controller, isDark, primaryColor), + ], + isDark, + primaryColor, + ), ], ); } - Widget _buildPage3(ProfileController controller, bool isDark) { + Widget _buildPage3( + ProfileController controller, + bool isDark, + Color primaryColor, + ) { return ListView( // 添加底部内边距,让内容延伸到导航栏下方,实现玻璃效果 padding: EdgeInsets.only( @@ -443,38 +482,48 @@ class ProfilePage extends StatelessWidget { bottom: AppConfig.liquidGlassTotalHeight + 16, ), children: [ - _buildSettingsGroup('用户体验计划(限免)', [ - _buildSettingsItem( - '加入体验', - Icons.edit, - () => Get.to(const UserPlanPage()), - isDark, - ), - _buildSettingsItem( - '参与投票', - Icons.how_to_vote, - () => Get.to(const VotePage()), - isDark, - ), - _buildSettingsItem( - '查看全站统计', - Icons.history, - () => Get.to(const EntirePage()), - isDark, - ), - _buildSettingsItem( - '开发计划', - Icons.analytics, - () => controller.showSnackBar('首个上线版本暂无计划,待收集整理用户建议'), - isDark, - ), - _buildSettingsItem( - '去投稿', - Icons.edit_note, - () => Get.to(const ManuscriptPage()), - isDark, - ), - ], isDark), + _buildSettingsGroup( + '用户体验计划(限免)', + [ + _buildSettingsItem( + '加入体验', + Icons.edit, + () => Get.to(const UserPlanPage()), + isDark, + primaryColor, + ), + _buildSettingsItem( + '参与投票', + Icons.how_to_vote, + () => Get.to(const VotePage()), + isDark, + primaryColor, + ), + _buildSettingsItem( + '查看全站统计', + Icons.history, + () => Get.to(const EntirePage()), + isDark, + primaryColor, + ), + _buildSettingsItem( + '开发计划', + Icons.analytics, + () => controller.showSnackBar('首个上线版本暂无计划,待收集整理用户建议'), + isDark, + primaryColor, + ), + _buildSettingsItem( + '去投稿', + Icons.edit_note, + () => Get.to(const ManuscriptPage()), + isDark, + primaryColor, + ), + ], + isDark, + primaryColor, + ), const SizedBox(height: 16), Container( padding: const EdgeInsets.all(20), @@ -496,12 +545,12 @@ class ProfilePage extends StatelessWidget { children: [ Row( children: [ - Icon(Icons.info, color: AppConstants.primaryColor, size: 20), + Icon(Icons.info, color: primaryColor, size: 20), const SizedBox(width: 8), Text( '关于应用', style: TextStyle( - color: AppConstants.primaryColor, + color: primaryColor, fontSize: 16, fontWeight: FontWeight.bold, ), @@ -568,7 +617,12 @@ class ProfilePage extends StatelessWidget { ); } - Widget _buildSettingsGroup(String title, List items, bool isDark) { + Widget _buildSettingsGroup( + String title, + List items, + bool isDark, + Color primaryColor, + ) { return Container( decoration: BoxDecoration( color: isDark ? const Color(0xFF2A2A2A) : Colors.white, @@ -590,16 +644,12 @@ class ProfilePage extends StatelessWidget { padding: const EdgeInsets.all(16), child: Row( children: [ - Icon( - Icons.settings_outlined, - color: AppConstants.primaryColor, - size: 20, - ), + Icon(Icons.settings_outlined, color: primaryColor, size: 20), const SizedBox(width: 8), Text( title, style: TextStyle( - color: AppConstants.primaryColor, + color: primaryColor, fontSize: 16, fontWeight: FontWeight.bold, ), @@ -619,9 +669,10 @@ class ProfilePage extends StatelessWidget { IconData icon, VoidCallback onTap, bool isDark, + Color primaryColor, ) { return ListTile( - leading: Icon(icon, color: AppConstants.primaryColor, size: 20), + leading: Icon(icon, color: primaryColor, size: 20), title: Text( title, style: TextStyle( @@ -641,17 +692,17 @@ class ProfilePage extends StatelessWidget { ); } - Widget _buildScreenWakeItem(ProfileController controller, bool isDark) { + Widget _buildScreenWakeItem( + ProfileController controller, + bool isDark, + Color primaryColor, + ) { if (kIsWeb) { return const SizedBox.shrink(); } return ListTile( - leading: Icon( - Icons.screen_lock_rotation, - color: AppConstants.primaryColor, - size: 20, - ), + leading: Icon(Icons.screen_lock_rotation, color: primaryColor, size: 20), title: Text( '屏幕常亮', style: TextStyle( @@ -680,7 +731,7 @@ class ProfilePage extends StatelessWidget { style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, - color: AppConstants.primaryColor, + color: primaryColor, ), ), content: Column( @@ -713,7 +764,7 @@ class ProfilePage extends StatelessWidget { Get.back(result: true); }, style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: primaryColor, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), @@ -734,22 +785,27 @@ class ProfilePage extends StatelessWidget { await controller.toggleScreenWake(value); } }, - activeColor: AppConstants.primaryColor, + activeColor: primaryColor, ), ), ); } - Widget _buildInteractionItem(String label, String value, bool isDark) { + Widget _buildInteractionItem( + String label, + String value, + bool isDark, + Color primaryColor, + ) { return Expanded( child: Column( children: [ Text( value, - style: const TextStyle( + style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, - color: AppConstants.primaryColor, + color: primaryColor, ), ), const SizedBox(height: 4), diff --git a/lib/views/profile/settings/app_fun.dart b/lib/views/profile/settings/app_fun.dart index 9907274..31fdc4b 100644 --- a/lib/views/profile/settings/app_fun.dart +++ b/lib/views/profile/settings/app_fun.dart @@ -8,8 +8,7 @@ import '../../../services/get/tap_liquid_glass_controller.dart'; import '../../../utils/audio_manager.dart'; import './widgets.dart'; import '../../home/set/home-load.dart'; -import '../../profile/theme/app-diy.dart'; -import '../../footprint/collect_notes.dart'; +import '../../../controllers/settings/suggestions.dart'; import '../../../controllers/load/locally.dart'; /// 时间: 2026-03-26 @@ -127,6 +126,7 @@ class _AppFunSettingsPageState extends State { // 显示震动提示对话框 void _showVibrationDialog() { + final primaryColor = _themeController.currentThemeColor; showDialog( context: context, builder: (context) => AlertDialog( @@ -146,10 +146,7 @@ class _AppFunSettingsPageState extends State { }); } }, - child: Text( - '确定', - style: TextStyle(color: AppConstants.primaryColor), - ), + child: Text('确定', style: TextStyle(color: primaryColor)), ), ], ), @@ -178,6 +175,7 @@ class _AppFunSettingsPageState extends State { Widget build(BuildContext context) { return Obx(() { final isDark = _themeController.isDarkMode; + final primaryColor = _themeController.currentThemeColor; return Scaffold( backgroundColor: isDark ? const Color(0xFF1A1A1A) @@ -185,16 +183,13 @@ class _AppFunSettingsPageState extends State { appBar: AppBar( title: Text( '功能设置', - style: TextStyle( - color: AppConstants.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold), ), backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, elevation: 0, centerTitle: true, leading: IconButton( - icon: Icon(Icons.arrow_back, color: AppConstants.primaryColor), + icon: Icon(Icons.arrow_back, color: primaryColor), onPressed: () => Navigator.of(context).pop(), ), ), @@ -310,13 +305,14 @@ class _AppFunSettingsPageState extends State { } Widget _buildSettingsGroup(String title, List items, bool isDark) { + final primaryColor = _themeController.currentThemeColor; return Container( decoration: BoxDecoration( color: isDark ? const Color(0xFF2A2A2A) : Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( - color: Colors.black.withValues(alpha: isDark ? 0.3 : 0.05), + color: Colors.black.withAlpha(isDark ? 30 : 5), blurRadius: 10, offset: const Offset(0, 2), ), @@ -332,7 +328,7 @@ class _AppFunSettingsPageState extends State { style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, - color: AppConstants.primaryColor, + color: primaryColor, ), ), ), @@ -350,14 +346,15 @@ class _AppFunSettingsPageState extends State { ValueChanged onChanged, bool isDark, ) { + final primaryColor = _themeController.currentThemeColor; return ListTile( leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: primaryColor.withAlpha(10), borderRadius: BorderRadius.circular(8), ), - child: Icon(icon, color: AppConstants.primaryColor, size: 20), + child: Icon(icon, color: primaryColor, size: 20), ), title: Text( title, @@ -377,20 +374,21 @@ class _AppFunSettingsPageState extends State { trailing: Switch( value: value, onChanged: onChanged, - activeThumbColor: AppConstants.primaryColor, + activeThumbColor: primaryColor, ), ); } Widget _buildFontSliderItem(bool isDark) { + final primaryColor = _themeController.currentThemeColor; return ListTile( leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: primaryColor.withAlpha(10), borderRadius: BorderRadius.circular(8), ), - child: Icon(Icons.widgets, color: AppConstants.primaryColor, size: 20), + child: Icon(Icons.widgets, color: primaryColor, size: 20), ), title: Text( '桌面卡片', @@ -419,7 +417,7 @@ class _AppFunSettingsPageState extends State { backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, title: Row( children: [ - Icon(Icons.info_outline, color: AppConstants.primaryColor), + Icon(Icons.info_outline, color: primaryColor), const SizedBox(width: 8), Text( '桌面卡片设置', @@ -491,7 +489,7 @@ class _AppFunSettingsPageState extends State { ); }, style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: primaryColor, foregroundColor: Colors.white, ), child: const Text('仍要进入'), @@ -505,6 +503,7 @@ class _AppFunSettingsPageState extends State { } Widget _buildTransparencyLevelItem(bool isDark) { + final primaryColor = _themeController.currentThemeColor; return Obx(() { final currentIndex = _glassController.transparencyLevelIndex; return Column( @@ -517,14 +516,10 @@ class _AppFunSettingsPageState extends State { Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: primaryColor.withAlpha(10), borderRadius: BorderRadius.circular(8), ), - child: Icon( - Icons.opacity, - color: AppConstants.primaryColor, - size: 20, - ), + child: Icon(Icons.opacity, color: primaryColor, size: 20), ), const SizedBox(width: 12), Expanded( @@ -575,6 +570,7 @@ class _AppFunSettingsPageState extends State { bool isSelected, bool isDark, ) { + final primaryColor = _themeController.currentThemeColor; return Expanded( child: GestureDetector( onTap: () => _glassController.setTransparencyLevelByIndex(levelIndex), @@ -582,12 +578,12 @@ class _AppFunSettingsPageState extends State { padding: const EdgeInsets.symmetric(vertical: 10), decoration: BoxDecoration( color: isSelected - ? AppConstants.primaryColor + ? primaryColor : (isDark ? Colors.grey[800] : Colors.grey[200]), borderRadius: BorderRadius.circular(8), border: Border.all( color: isSelected - ? AppConstants.primaryColor + ? primaryColor : (isDark ? Colors.grey[700]! : Colors.grey[300]!), width: 1.5, ), @@ -615,14 +611,15 @@ class _AppFunSettingsPageState extends State { VoidCallback onTap, bool isDark, ) { + final primaryColor = _themeController.currentThemeColor; return ListTile( leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: primaryColor.withAlpha(10), borderRadius: BorderRadius.circular(8), ), - child: Icon(icon, color: AppConstants.primaryColor, size: 20), + child: Icon(icon, color: primaryColor, size: 20), ), title: Text( title, @@ -648,70 +645,7 @@ class _AppFunSettingsPageState extends State { } Widget _buildVersionInfo(bool isDark) { - return Container( - padding: const EdgeInsets.all(20), - decoration: BoxDecoration( - color: isDark ? const Color(0xFF2A2A2A) : Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: isDark ? 0.3 : 0.05), - blurRadius: 10, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - children: [ - Icon( - Icons.settings_suggest, - size: 40, - color: AppConstants.primaryColor, - ), - const SizedBox(height: 12), - Text( - '设置建议', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: isDark ? Colors.white : Colors.black, - ), - ), - const SizedBox(height: 4), - Text( - '是否在找,主题风格', - style: TextStyle( - fontSize: 13, - color: isDark ? Colors.grey[400] : Colors.grey[600], - ), - ), - const SizedBox(height: 16), - Row( - children: [ - Expanded( - child: _buildActionButton( - '主题风格', - '自定义应用主题', - Icons.palette, - Colors.blue, - () => Get.to(() => const AppDiyPage()), - ), - ), - const SizedBox(width: 12), - Expanded( - child: _buildActionButton( - '创建笔记', - '快速创建新笔记', - Icons.note_add, - Colors.green, - () => Get.to(() => const CollectNotesPage()), - ), - ), - ], - ), - ], - ), - ); + return const SuggestionsCard(); } Widget _buildActionButton( diff --git a/lib/views/profile/settings/learn-us.dart b/lib/views/profile/settings/learn-us.dart index 892ea2d..36836ea 100644 --- a/lib/views/profile/settings/learn-us.dart +++ b/lib/views/profile/settings/learn-us.dart @@ -19,6 +19,7 @@ class LearnUsPage extends StatelessWidget { return Obx(() { final isDark = themeController.isDarkMode; + final primaryColor = themeController.currentThemeColor; return Scaffold( backgroundColor: isDark ? const Color(0xFF1A1A1A) @@ -26,16 +27,13 @@ class LearnUsPage extends StatelessWidget { appBar: AppBar( title: Text( '了解我们', - style: TextStyle( - color: AppConstants.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold), ), backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, elevation: 0, centerTitle: true, leading: IconButton( - icon: Icon(Icons.arrow_back, color: AppConstants.primaryColor), + icon: Icon(Icons.arrow_back, color: primaryColor), onPressed: () => Navigator.of(context).pop(), ), ), @@ -62,14 +60,16 @@ class LearnUsPage extends StatelessWidget { } Widget _buildHeaderCard() { + final themeController = Get.find(); + final primaryColor = themeController.currentThemeColor; return Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( - gradient: const LinearGradient( + gradient: LinearGradient( colors: [ - Color.fromARGB(255, 143, 73, 228), - Color(0xFF6200EE), - Color(0xFF3700B3), + primaryColor.withAlpha(200), + primaryColor, + primaryColor.withAlpha(150), ], begin: Alignment.topLeft, end: Alignment.bottomRight, @@ -77,7 +77,7 @@ class LearnUsPage extends StatelessWidget { borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( - color: AppConstants.primaryColor.withValues(alpha: 0.3), + color: primaryColor.withAlpha(30), blurRadius: 12, offset: const Offset(0, 4), ), @@ -155,6 +155,8 @@ class LearnUsPage extends StatelessWidget { } Widget _buildOfficialSiteCard(bool isDark) { + final themeController = Get.find(); + final primaryColor = themeController.currentThemeColor; return Container( decoration: BoxDecoration( color: isDark ? const Color(0xFF2A2A2A) : Colors.white, @@ -162,8 +164,8 @@ class LearnUsPage extends StatelessWidget { boxShadow: [ BoxShadow( color: isDark - ? Colors.black.withValues(alpha: 0.3) - : Colors.black.withValues(alpha: 0.05), + ? Colors.black.withAlpha(30) + : Colors.black.withAlpha(5), blurRadius: 10, offset: const Offset(0, 2), ), @@ -179,14 +181,10 @@ class LearnUsPage extends StatelessWidget { Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: Colors.blue.withValues(alpha: 0.1), + color: primaryColor.withAlpha(10), borderRadius: BorderRadius.circular(8), ), - child: Icon( - Icons.language, - color: Colors.blue[700], - size: 20, - ), + child: Icon(Icons.language, color: primaryColor, size: 20), ), const SizedBox(width: 12), Text( @@ -222,25 +220,18 @@ class LearnUsPage extends StatelessWidget { borderRadius: BorderRadius.circular(8), border: Border.all( color: isDark - ? Colors.grey[700]!.withValues(alpha: 0.2) - : Colors.grey.withValues(alpha: 0.2), + ? Colors.grey[700]!.withAlpha(20) + : Colors.grey.withAlpha(20), ), ), child: Row( children: [ - Icon( - Icons.link, - size: 16, - color: AppConstants.primaryColor, - ), + Icon(Icons.link, size: 16, color: primaryColor), const SizedBox(width: 8), Expanded( child: Text( 'https://poe.vogov.cn/app.html', - style: TextStyle( - fontSize: 14, - color: AppConstants.primaryColor, - ), + style: TextStyle(fontSize: 14, color: primaryColor), ), ), ], @@ -255,6 +246,8 @@ class LearnUsPage extends StatelessWidget { } Widget _buildQQGroupCard(BuildContext context, bool isDark) { + final themeController = Get.find(); + final primaryColor = themeController.currentThemeColor; return Container( decoration: BoxDecoration( color: isDark ? const Color(0xFF2A2A2A) : Colors.white, @@ -262,8 +255,8 @@ class LearnUsPage extends StatelessWidget { boxShadow: [ BoxShadow( color: isDark - ? Colors.black.withValues(alpha: 0.3) - : Colors.black.withValues(alpha: 0.05), + ? Colors.black.withAlpha(30) + : Colors.black.withAlpha(5), blurRadius: 10, offset: const Offset(0, 2), ), @@ -279,10 +272,10 @@ class LearnUsPage extends StatelessWidget { Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: Colors.blue.withValues(alpha: 0.1), + color: primaryColor.withAlpha(10), borderRadius: BorderRadius.circular(8), ), - child: Icon(Icons.group, color: Colors.blue[700], size: 20), + child: Icon(Icons.group, color: primaryColor, size: 20), ), const SizedBox(width: 12), Text( @@ -319,25 +312,19 @@ class LearnUsPage extends StatelessWidget { decoration: BoxDecoration( color: isDark ? const Color(0xFF3A3A3A) : Colors.grey[50], borderRadius: BorderRadius.circular(8), - border: Border.all( - color: AppConstants.primaryColor.withValues(alpha: 0.3), - ), + border: Border.all(color: primaryColor.withAlpha(30)), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( - Icons.content_copy, - size: 16, - color: AppConstants.primaryColor, - ), + Icon(Icons.content_copy, size: 16, color: primaryColor), const SizedBox(width: 8), Text( '271129018', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w600, - color: AppConstants.primaryColor, + color: primaryColor, ), ), ], @@ -361,6 +348,8 @@ class LearnUsPage extends StatelessWidget { } void _copyQQGroupNumber(BuildContext context) { + final themeController = Get.find(); + final primaryColor = themeController.currentThemeColor; Clipboard.setData(const ClipboardData(text: '271129018')); ScaffoldMessenger.of(context).showSnackBar( @@ -372,7 +361,7 @@ class LearnUsPage extends StatelessWidget { Text('QQ群号已复制到剪贴板'), ], ), - backgroundColor: AppConstants.primaryColor, + backgroundColor: primaryColor, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), duration: const Duration(seconds: 2), @@ -381,6 +370,8 @@ class LearnUsPage extends StatelessWidget { } Widget _buildDeveloperCard(BuildContext context, bool isDark) { + final themeController = Get.find(); + final primaryColor = themeController.currentThemeColor; return Container( decoration: BoxDecoration( color: isDark ? const Color(0xFF2A2A2A) : Colors.white, @@ -388,8 +379,8 @@ class LearnUsPage extends StatelessWidget { boxShadow: [ BoxShadow( color: isDark - ? Colors.black.withValues(alpha: 0.3) - : Colors.black.withValues(alpha: 0.05), + ? Colors.black.withAlpha(30) + : Colors.black.withAlpha(5), blurRadius: 10, offset: const Offset(0, 2), ), @@ -405,14 +396,10 @@ class LearnUsPage extends StatelessWidget { Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: Colors.green.withValues(alpha: 0.1), + color: primaryColor.withAlpha(10), borderRadius: BorderRadius.circular(8), ), - child: Icon( - Icons.business, - color: Colors.green[700], - size: 20, - ), + child: Icon(Icons.business, color: primaryColor, size: 20), ), const SizedBox(width: 12), Text( @@ -437,8 +424,8 @@ class LearnUsPage extends StatelessWidget { decoration: BoxDecoration( gradient: LinearGradient( colors: [ - AppConstants.primaryColor.withValues(alpha: 0.1), - AppConstants.primaryColor.withValues(alpha: 0.05), + primaryColor.withAlpha(10), + primaryColor.withAlpha(5), ], ), borderRadius: BorderRadius.circular(12), @@ -666,7 +653,7 @@ class LearnUsPage extends StatelessWidget { '尽毕生所学,取天下之诗集,只为逗她一笑', isDark, ), - _buildTeamMember('🎨', 'UI/UX/Testing', 'Ayk', '....', isDark), + _buildTeamMember('🎨', 'UI/UX/Testing', 'Ayk', '姥头乐也疯狂', isDark), _buildTeamMember('⚙️', '后端', '伯乐不相马', '真的吗,还是做不到吗?', isDark), _buildTeamMember('🔧', '技术支持', '闲言app', '闲言app原班人马打造', isDark), ], @@ -681,6 +668,8 @@ class LearnUsPage extends StatelessWidget { String signature, bool isDark, ) { + final themeController = Get.find(); + final primaryColor = themeController.currentThemeColor; return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Row( @@ -718,15 +707,12 @@ class LearnUsPage extends StatelessWidget { vertical: 2, ), decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: primaryColor.withAlpha(10), borderRadius: BorderRadius.circular(10), ), child: Text( name, - style: TextStyle( - fontSize: 11, - color: AppConstants.primaryColor, - ), + style: TextStyle(fontSize: 11, color: primaryColor), ), ), ], @@ -814,7 +800,7 @@ class LearnUsPage extends StatelessWidget { children: [ Expanded( child: Text( - '滇ICP备2022000863号-13', + '滇ICP备2022000863号-15A', style: TextStyle( fontSize: 14, color: isDark ? Colors.grey[300] : Colors.grey[700], diff --git a/lib/views/profile/settings/offline-data.dart b/lib/views/profile/settings/offline-data.dart index 7bb1136..d738700 100644 --- a/lib/views/profile/settings/offline-data.dart +++ b/lib/views/profile/settings/offline-data.dart @@ -153,7 +153,7 @@ class _OfflineDataPageState extends State { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('已保存 $_downloadedCount 条数据'), - backgroundColor: AppConstants.primaryColor, + backgroundColor: _themeController.currentThemeColor, ), ); } @@ -265,7 +265,7 @@ class _OfflineDataPageState extends State { content: Text( '成功缓存 ${_selectedType == DownloadType.poetry ? '诗词' : '答题'} $_cachedCount 条数据', ), - backgroundColor: AppConstants.primaryColor, + backgroundColor: _themeController.currentThemeColor, ), ); } @@ -371,7 +371,7 @@ class _OfflineDataPageState extends State { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('已清空$typeName离线数据'), - backgroundColor: AppConstants.primaryColor, + backgroundColor: _themeController.currentThemeColor, ), ); } @@ -401,9 +401,9 @@ class _OfflineDataPageState extends State { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('已清空所有离线数据'), - backgroundColor: AppConstants.primaryColor, + SnackBar( + content: const Text('已清空所有离线数据'), + backgroundColor: _themeController.currentThemeColor, ), ); } @@ -515,6 +515,7 @@ class _OfflineDataPageState extends State { Widget build(BuildContext context) { return Obx(() { final isDark = _themeController.isDarkMode; + final primaryColor = _themeController.currentThemeColor; return Scaffold( backgroundColor: isDark ? const Color(0xFF1A1A1A) @@ -522,24 +523,18 @@ class _OfflineDataPageState extends State { appBar: AppBar( title: Text( '离线使用', - style: TextStyle( - color: AppConstants.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold), ), backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, elevation: 0, centerTitle: true, leading: IconButton( - icon: Icon(Icons.arrow_back, color: AppConstants.primaryColor), + icon: Icon(Icons.arrow_back, color: primaryColor), onPressed: () => Navigator.of(context).pop(), ), actions: [ IconButton( - icon: Icon( - Icons.cloud_outlined, - color: AppConstants.primaryColor, - ), + icon: Icon(Icons.cloud_outlined, color: primaryColor), onPressed: _showServerInfo, tooltip: '服务器信息', ), @@ -555,7 +550,7 @@ class _OfflineDataPageState extends State { borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( - color: Colors.black.withValues(alpha: isDark ? 0.3 : 0.05), + color: Colors.black.withAlpha(isDark ? 30 : 5), blurRadius: 10, offset: const Offset(0, 2), ), @@ -565,11 +560,7 @@ class _OfflineDataPageState extends State { children: [ Row( children: [ - Icon( - Icons.download_done, - color: AppConstants.primaryColor, - size: 24, - ), + Icon(Icons.download_done, color: primaryColor, size: 24), const SizedBox(width: 12), Text( '缓存状态', @@ -615,7 +606,7 @@ class _OfflineDataPageState extends State { borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( - color: Colors.black.withValues(alpha: isDark ? 0.3 : 0.05), + color: Colors.black.withAlpha(isDark ? 30 : 5), blurRadius: 10, offset: const Offset(0, 2), ), @@ -626,11 +617,7 @@ class _OfflineDataPageState extends State { children: [ Row( children: [ - Icon( - Icons.category, - color: AppConstants.primaryColor, - size: 20, - ), + Icon(Icons.category, color: primaryColor, size: 20), const SizedBox(width: 8), Text( '下载类型', @@ -663,7 +650,7 @@ class _OfflineDataPageState extends State { borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( - color: Colors.black.withValues(alpha: isDark ? 0.3 : 0.05), + color: Colors.black.withAlpha(isDark ? 30 : 5), blurRadius: 10, offset: const Offset(0, 2), ), @@ -674,11 +661,7 @@ class _OfflineDataPageState extends State { children: [ Row( children: [ - Icon( - Icons.settings, - color: AppConstants.primaryColor, - size: 20, - ), + Icon(Icons.settings, color: primaryColor, size: 20), const SizedBox(width: 8), Text( '下载数量', @@ -720,9 +703,7 @@ class _OfflineDataPageState extends State { ? (_isCancelling ? null : _cancelDownload) : _downloadOfflineData, style: ElevatedButton.styleFrom( - backgroundColor: _isCancelling - ? Colors.red - : AppConstants.primaryColor, + backgroundColor: _isCancelling ? Colors.red : primaryColor, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), @@ -804,9 +785,7 @@ class _OfflineDataPageState extends State { backgroundColor: isDark ? Colors.grey[700] : Colors.grey[200], - valueColor: AlwaysStoppedAnimation( - AppConstants.primaryColor, - ), + valueColor: AlwaysStoppedAnimation(primaryColor), borderRadius: BorderRadius.circular(10), ), const SizedBox(height: 8), @@ -942,6 +921,7 @@ class _OfflineDataPageState extends State { Widget _buildTypeOption(DownloadType type, String label, bool isDark) { final isSelected = _selectedType == type; + final primaryColor = _themeController.currentThemeColor; return GestureDetector( onTap: () { setState(() { @@ -954,12 +934,12 @@ class _OfflineDataPageState extends State { padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12), decoration: BoxDecoration( color: isSelected - ? AppConstants.primaryColor + ? primaryColor : (isDark ? Colors.grey[800] : Colors.grey[100]), borderRadius: BorderRadius.circular(8), border: Border.all( color: isSelected - ? AppConstants.primaryColor + ? primaryColor : (isDark ? Colors.grey[700]! : Colors.grey[300]!), ), ), @@ -979,6 +959,7 @@ class _OfflineDataPageState extends State { Widget _buildCountOption(int count, bool isDark) { final isSelected = _selectedCount == count; + final primaryColor = _themeController.currentThemeColor; return Stack( children: [ GestureDetector( @@ -991,12 +972,12 @@ class _OfflineDataPageState extends State { padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: isSelected - ? AppConstants.primaryColor + ? primaryColor : (isDark ? Colors.grey[800] : Colors.grey[100]), borderRadius: BorderRadius.circular(8), border: Border.all( color: isSelected - ? AppConstants.primaryColor + ? primaryColor : (isDark ? Colors.grey[700]! : Colors.grey[300]!), ), ), diff --git a/lib/views/profile/settings/privacy.dart b/lib/views/profile/settings/privacy.dart index 192115e..cfd9688 100644 --- a/lib/views/profile/settings/privacy.dart +++ b/lib/views/profile/settings/privacy.dart @@ -52,6 +52,7 @@ class PrivacyPolicyContent extends StatelessWidget { _buildPermissionItem('网络权限', '用于获取诗词内容和更新应用信息'), _buildPermissionItem('震动权限', '用于在执行操作时提供反馈提示'), _buildPermissionItem('分享能力', '调用系统分享功能,分享您的笔记、收藏等本地数据'), + _buildPermissionItem('设备标识', '获取唯一标识设备的设备ID,确保用户数据安全。'), const SizedBox(height: 24), _buildSectionTitle('3. 管理您的个人信息'), const SizedBox(height: 16), @@ -125,6 +126,8 @@ class PrivacyPolicyContent extends StatelessWidget { } Widget _buildBulletPoint(String text) { + final themeController = Get.find(); + final primaryColor = themeController.currentThemeColor; return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( @@ -135,7 +138,7 @@ class PrivacyPolicyContent extends StatelessWidget { height: 6, margin: const EdgeInsets.only(top: 6, left: 8, right: 12), decoration: BoxDecoration( - color: AppConstants.primaryColor, + color: primaryColor, shape: BoxShape.circle, ), ), @@ -487,6 +490,7 @@ class _PrivacyPageState extends State Widget build(BuildContext context) { return Obx(() { final isDark = _themeController.isDarkMode; + final primaryColor = _themeController.currentThemeColor; return Scaffold( backgroundColor: isDark ? const Color(0xFF1A1A1A) @@ -494,19 +498,16 @@ class _PrivacyPageState extends State appBar: AppBar( title: Text( '隐私与协议', - style: TextStyle( - color: AppConstants.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold), ), backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, elevation: 0, centerTitle: true, bottom: TabBar( controller: _tabController, - labelColor: AppConstants.primaryColor, + labelColor: primaryColor, unselectedLabelColor: isDark ? Colors.grey[400] : Colors.grey[600], - indicatorColor: AppConstants.primaryColor, + indicatorColor: primaryColor, indicatorWeight: 2, tabs: const [ Tab(text: '隐私政策'), @@ -514,12 +515,12 @@ class _PrivacyPageState extends State ], ), leading: IconButton( - icon: Icon(Icons.arrow_back, color: AppConstants.primaryColor), + icon: Icon(Icons.arrow_back, color: primaryColor), onPressed: () => Navigator.of(context).pop(), ), actions: [ IconButton( - icon: Icon(Icons.link, color: AppConstants.primaryColor), + icon: Icon(Icons.link, color: primaryColor), onPressed: () => _showOnlineLinkDialog(isDark), tooltip: '在线版本', ), @@ -537,6 +538,7 @@ class _PrivacyPageState extends State } void _showOnlineLinkDialog(bool isDark) { + final primaryColor = _themeController.currentThemeColor; showDialog( context: context, builder: (context) => AlertDialog( @@ -544,7 +546,7 @@ class _PrivacyPageState extends State shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), title: Row( children: [ - Icon(Icons.public, color: AppConstants.primaryColor), + Icon(Icons.public, color: primaryColor), const SizedBox(width: 8), Text( '在线版本', @@ -577,7 +579,7 @@ class _PrivacyPageState extends State 'https://poe.vogov.cn/privacy.html', style: TextStyle( fontSize: 13, - color: AppConstants.primaryColor, + color: primaryColor, decoration: TextDecoration.underline, ), ), @@ -609,7 +611,7 @@ class _PrivacyPageState extends State ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: const Text('链接已复制到剪贴板'), - backgroundColor: AppConstants.primaryColor, + backgroundColor: primaryColor, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), @@ -620,7 +622,7 @@ class _PrivacyPageState extends State icon: const Icon(Icons.copy, size: 18), label: const Text('复制链接'), style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: primaryColor, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), diff --git a/lib/views/profile/settings/user-plan.dart b/lib/views/profile/settings/user-plan.dart index 27e2b1d..2656b7e 100644 --- a/lib/views/profile/settings/user-plan.dart +++ b/lib/views/profile/settings/user-plan.dart @@ -46,20 +46,23 @@ class _UserPlanPageState extends State { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(value ? '已加入用户体验计划' : '已退出用户体验计划'), - backgroundColor: value ? AppConstants.primaryColor : Colors.grey[600], + backgroundColor: value + ? _themeController.currentThemeColor + : Colors.grey[600], ), ); } } void _showJoinDialog() { + final primaryColor = _themeController.currentThemeColor; showDialog( context: context, builder: (context) => AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), title: Row( children: [ - Icon(Icons.volunteer_activism, color: AppConstants.primaryColor), + Icon(Icons.volunteer_activism, color: primaryColor), const SizedBox(width: 8), const Text('加入用户体验计划'), ], @@ -96,7 +99,7 @@ class _UserPlanPageState extends State { _toggleUserPlan(true); }, style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: primaryColor, foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), @@ -110,13 +113,14 @@ class _UserPlanPageState extends State { } void _showInfoPopup(BuildContext context) { + final primaryColor = _themeController.currentThemeColor; showDialog( context: context, builder: (context) => AlertDialog( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), title: Row( children: [ - Icon(Icons.info, color: AppConstants.primaryColor), + Icon(Icons.info, color: primaryColor), const SizedBox(width: 8), const Text('温馨提示'), ], @@ -192,6 +196,7 @@ class _UserPlanPageState extends State { Widget build(BuildContext context) { return Obx(() { final isDark = _themeController.isDarkMode; + final primaryColor = _themeController.currentThemeColor; return Scaffold( backgroundColor: isDark ? const Color(0xFF1A1A1A) @@ -199,16 +204,13 @@ class _UserPlanPageState extends State { appBar: AppBar( title: Text( '用户体验计划', - style: TextStyle( - color: AppConstants.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold), ), backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, elevation: 0, centerTitle: true, leading: IconButton( - icon: Icon(Icons.arrow_back, color: AppConstants.primaryColor), + icon: Icon(Icons.arrow_back, color: primaryColor), onPressed: () => Navigator.of(context).pop(), ), ), @@ -235,21 +237,19 @@ class _UserPlanPageState extends State { } Widget _buildStatusCard(bool isDark) { + final primaryColor = _themeController.currentThemeColor; return Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( gradient: LinearGradient( - colors: [ - AppConstants.primaryColor, - AppConstants.primaryColor.withBlue(180), - ], + colors: [primaryColor, primaryColor.withBlue(180)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( - color: AppConstants.primaryColor.withValues(alpha: 0.3), + color: primaryColor.withAlpha(30), blurRadius: 12, offset: const Offset(0, 4), ), @@ -531,6 +531,7 @@ class _UserPlanPageState extends State { itemCount: benefits.length, itemBuilder: (context, index) { final benefit = benefits[index]; + final primaryColor = _themeController.currentThemeColor; return Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( @@ -539,7 +540,7 @@ class _UserPlanPageState extends State { border: Border.all( color: isDark ? Colors.grey[700]! - : Colors.grey.withValues(alpha: 0.2), + : Colors.grey.withAlpha(20), ), ), child: Row( @@ -547,7 +548,7 @@ class _UserPlanPageState extends State { Icon( benefit['icon'] as IconData, size: 18, - color: AppConstants.primaryColor, + color: primaryColor, ), const SizedBox(width: 8), Expanded( @@ -660,6 +661,7 @@ class _UserPlanPageState extends State { } Widget _buildActionButton(bool isDark) { + final primaryColor = _themeController.currentThemeColor; return Container( width: double.infinity, height: 50, @@ -667,10 +669,7 @@ class _UserPlanPageState extends State { gradient: _isJoined ? null : LinearGradient( - colors: [ - AppConstants.primaryColor, - AppConstants.primaryColor.withBlue(180), - ], + colors: [primaryColor, primaryColor.withBlue(180)], ), color: _isJoined ? (isDark ? Colors.grey[700] : Colors.grey[300]) @@ -680,7 +679,7 @@ class _UserPlanPageState extends State { ? null : [ BoxShadow( - color: AppConstants.primaryColor.withValues(alpha: 0.3), + color: primaryColor.withAlpha(30), blurRadius: 8, offset: const Offset(0, 4), ), diff --git a/lib/views/profile/settings/widgets.dart b/lib/views/profile/settings/widgets.dart index 82b9100..94f06d6 100644 --- a/lib/views/profile/settings/widgets.dart +++ b/lib/views/profile/settings/widgets.dart @@ -27,6 +27,7 @@ class _WidgetsPageState extends State { Widget build(BuildContext context) { return Obx(() { final isDark = _themeController.isDarkMode; + final primaryColor = _themeController.currentThemeColor; return Scaffold( backgroundColor: isDark ? const Color(0xFF1A1A1A) @@ -34,16 +35,13 @@ class _WidgetsPageState extends State { appBar: AppBar( title: Text( '桌面卡片设置', - style: TextStyle( - color: AppConstants.primaryColor, - fontWeight: FontWeight.bold, - ), + style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold), ), backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, elevation: 0, centerTitle: true, leading: IconButton( - icon: Icon(Icons.arrow_back, color: AppConstants.primaryColor), + icon: Icon(Icons.arrow_back, color: primaryColor), onPressed: () => Navigator.of(context).pop(), ), ), @@ -100,6 +98,7 @@ class _WidgetsPageState extends State { } Widget _buildSettingsGroup(String title, List items, bool isDark) { + final primaryColor = _themeController.currentThemeColor; return Container( decoration: BoxDecoration( color: isDark ? const Color(0xFF2A2A2A) : Colors.white, @@ -122,7 +121,7 @@ class _WidgetsPageState extends State { style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, - color: AppConstants.primaryColor, + color: primaryColor, ), ), ), @@ -140,14 +139,15 @@ class _WidgetsPageState extends State { ValueChanged onChanged, bool isDark, ) { + final primaryColor = _themeController.currentThemeColor; return ListTile( leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: AppConstants.primaryColor.withAlpha(10), + color: primaryColor.withAlpha(10), borderRadius: BorderRadius.circular(8), ), - child: Icon(icon, color: AppConstants.primaryColor, size: 20), + child: Icon(icon, color: primaryColor, size: 20), ), title: Text( title, @@ -167,20 +167,21 @@ class _WidgetsPageState extends State { trailing: Switch( value: value, onChanged: onChanged, - activeThumbColor: AppConstants.primaryColor, + activeThumbColor: primaryColor, ), ); } Widget _buildIntervalItem(bool isDark) { + final primaryColor = _themeController.currentThemeColor; return ListTile( leading: Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( - color: AppConstants.primaryColor.withAlpha(10), + color: primaryColor.withAlpha(10), borderRadius: BorderRadius.circular(8), ), - child: Icon(Icons.refresh, color: AppConstants.primaryColor, size: 20), + child: Icon(Icons.refresh, color: primaryColor, size: 20), ), title: Text( '更新间隔', @@ -213,7 +214,7 @@ class _WidgetsPageState extends State { visualDensity: VisualDensity.compact, backgroundColor: WidgetStateProperty.resolveWith((states) { if (states.contains(WidgetState.selected)) { - return AppConstants.primaryColor; + return primaryColor; } return isDark ? Colors.grey[700] : Colors.grey[200]; }), @@ -230,11 +231,12 @@ class _WidgetsPageState extends State { } Widget _buildPreviewCard(bool isDark) { + final primaryColor = _themeController.currentThemeColor; return Container( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: const EdgeInsets.all(16), decoration: BoxDecoration( - color: AppConstants.primaryColor.withAlpha(90), + color: primaryColor.withAlpha(90), borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( @@ -303,19 +305,17 @@ class _WidgetsPageState extends State { } Widget _buildActionButton(bool isDark) { + final primaryColor = _themeController.currentThemeColor; return SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () { ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('桌面卡片设置已保存'), - backgroundColor: AppConstants.primaryColor, - ), + SnackBar(content: Text('桌面卡片设置已保存'), backgroundColor: primaryColor), ); }, style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: primaryColor, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), diff --git a/lib/views/profile/theme/app-diy.dart b/lib/views/profile/theme/app-diy.dart index eb923c8..8fae115 100644 --- a/lib/views/profile/theme/app-diy.dart +++ b/lib/views/profile/theme/app-diy.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../../../constants/app_constants.dart'; +import '../../../models/colors/theme_colors.dart'; import '../../../services/get/theme_controller.dart'; /// 时间: 2026-03-27 @@ -29,23 +30,10 @@ class _AppDiyPageState extends State { late Timer _scrollTimer; // 主题颜色选项 - final List _themeColors = [ - AppConstants.primaryColor, // 默认紫色 - Colors.blue, // 蓝色 - Colors.green, // 绿色 - Colors.orange, // 橙色 - Colors.red, // 红色 - Colors.teal, // 青色 - ]; + final List _themeColors = ThemeColors.themeColors; // 强调色选项 - final List _accentColors = [ - AppConstants.primaryColor, // 默认紫色 - Colors.yellow, // 黄色 - Colors.pink, // 粉色 - Colors.cyan, // 青色 - Colors.purple, // 深紫色 - ]; + final List _accentColors = ThemeColors.accentColors; // 字体大小选项 final List _fontSizes = ['小', '中', '大']; @@ -72,31 +60,68 @@ class _AppDiyPageState extends State { context: context, barrierDismissible: false, builder: (BuildContext context) { + final primaryColor = _themeController.currentThemeColor; + final isDark = _themeController.isDarkMode; + return AlertDialog( + backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), title: Row( children: [ - Icon(Icons.construction, color: AppConstants.primaryColor), + Icon(Icons.construction, color: primaryColor), const SizedBox(width: 8), - const Text('开发中'), + Text( + '开发中', + style: TextStyle(color: isDark ? Colors.white : Colors.black), + ), ], ), - content: const Column( + content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '个性化设置开发中', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16), + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + color: isDark ? Colors.white : Colors.black, + ), ), - SizedBox(height: 12), - Text('• 当前仅支持设置深色模式'), - Text('• 其他设置仅当前页面生效'), - Text('• 后续版本将陆续支持'), - Text('• 可提前预览主题风格设置'), - SizedBox(height: 12), + const SizedBox(height: 12), + Text( + '• ✅ 深色模式(已支持)', + style: TextStyle( + color: isDark ? Colors.grey[300] : Colors.black87, + ), + ), + Text( + '• ✅ 主题色彩(已支持)', + style: TextStyle( + color: isDark ? Colors.grey[300] : Colors.black87, + ), + ), + Text( + '• ⏳ 其他设置仅当前页面生效', + style: TextStyle( + color: isDark ? Colors.grey[300] : Colors.black87, + ), + ), + Text( + '• ⏳ 后续版本将陆续支持', + style: TextStyle( + color: isDark ? Colors.grey[300] : Colors.black87, + ), + ), + const SizedBox(height: 12), Text( '感谢您的耐心等待!', - style: TextStyle(color: Colors.grey, fontSize: 12), + style: TextStyle( + color: isDark ? Colors.grey[400] : Colors.grey[600], + fontSize: 12, + ), ), ], ), @@ -104,8 +129,11 @@ class _AppDiyPageState extends State { ElevatedButton( onPressed: () => Navigator.of(context).pop(), style: ElevatedButton.styleFrom( - backgroundColor: AppConstants.primaryColor, + backgroundColor: primaryColor, foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), ), child: const Text('我知道了'), ), @@ -184,9 +212,11 @@ class _AppDiyPageState extends State { return Scaffold( appBar: AppBar( - title: const Text('个性化'), + title: Text( + '个性化', + style: TextStyle(color: _themeController.currentThemeColor), + ), backgroundColor: isDark ? Colors.grey[900] : Colors.white, - foregroundColor: isDark ? Colors.white : AppConstants.primaryColor, elevation: 0, ), backgroundColor: isDark ? Colors.grey[900] : Colors.grey[50], @@ -363,7 +393,7 @@ class _AppDiyPageState extends State { ], ), child: ListTile( - leading: Icon(icon, color: _themeColors[themeColorIdx]), + leading: Icon(icon, color: _themeController.currentThemeColor), title: Text( title, style: TextStyle(color: isDark ? Colors.white : Colors.black87), @@ -371,7 +401,7 @@ class _AppDiyPageState extends State { trailing: Switch( value: value, onChanged: onChanged, - activeThumbColor: _themeColors[themeColorIdx], + activeThumbColor: _themeController.currentThemeColor, ), ), ); @@ -400,7 +430,7 @@ class _AppDiyPageState extends State { ], ), child: ListTile( - leading: Icon(icon, color: _themeColors[themeColorIdx]), + leading: Icon(icon, color: _themeController.currentThemeColor), title: Text( title, style: TextStyle(color: isDark ? Colors.white : Colors.black87), @@ -428,6 +458,22 @@ class _AppDiyPageState extends State { ); } + // 颜色名称映射 + final Map _colorNames = { + AppConstants.primaryColor: '紫韵', + Colors.blue: '天蓝', + Colors.green: '翠绿', + Colors.orange: '橙光', + Colors.red: '朱红', + Colors.teal: '青碧', + const Color(0xFF8B4513): '书褐', + Colors.yellow: '明黄', + Colors.pink: '桃粉', + Colors.cyan: '湖青', + Colors.purple: '罗兰', + const Color(0xFFF5F5F0): '宣纸', + }; + Widget _buildColorSelector( String title, List colors, @@ -448,34 +494,103 @@ class _AppDiyPageState extends State { ), ], ), - child: ListTile( - title: Text( - title, - style: TextStyle(color: isDark ? Colors.white : Colors.black87), - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: colors.asMap().entries.map((entry) { - return GestureDetector( - onTap: () => onChanged(entry.key), - child: Container( - width: 32, - height: 32, - margin: const EdgeInsets.symmetric(horizontal: 4), - decoration: BoxDecoration( - color: entry.value, - shape: BoxShape.circle, - border: entry.key == selectedIndex - ? Border.all( - color: isDark ? Colors.white : Colors.black, - width: 2, - ) - : null, - ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(16, 12, 16, 8), + child: Text( + title, + style: TextStyle( + color: isDark ? Colors.white : Colors.black87, + fontSize: 16, + fontWeight: FontWeight.w500, ), - ); - }).toList(), - ), + ), + ), + SizedBox( + height: 80, + child: ListView.builder( + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.symmetric(horizontal: 12), + itemCount: colors.length, + itemBuilder: (context, index) { + final color = colors[index]; + final colorName = _colorNames[color] ?? '色彩${index + 1}'; + final isSelected = index == selectedIndex; + + return GestureDetector( + onTap: () => onChanged(index), + child: Container( + width: 60, + margin: const EdgeInsets.symmetric( + horizontal: 4, + vertical: 8, + ), + child: Column( + children: [ + Container( + width: 44, + height: 44, + decoration: BoxDecoration( + color: color, + shape: BoxShape.circle, + border: isSelected + ? Border.all( + color: isDark ? Colors.white : Colors.black, + width: 3, + ) + : Border.all( + color: isDark + ? Colors.grey[600]! + : Colors.grey[300]!, + width: 1, + ), + boxShadow: isSelected + ? [ + BoxShadow( + color: color.withAlpha(128), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ] + : null, + ), + child: isSelected + ? Icon( + Icons.check, + color: color.computeLuminance() > 0.5 + ? Colors.black + : Colors.white, + size: 24, + ) + : null, + ), + const SizedBox(height: 4), + Text( + colorName, + style: TextStyle( + fontSize: 11, + color: isSelected + ? (isDark ? Colors.white : Colors.black) + : (isDark + ? Colors.grey[400] + : Colors.grey[600]), + fontWeight: isSelected + ? FontWeight.w600 + : FontWeight.normal, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ), + ); + }, + ), + ), + ], ), ); } @@ -543,7 +658,6 @@ class _AppDiyPageState extends State { Icons.style, isMd: true, isDark: isDark, - themeColorIdx: themeColorIdx, ), const SizedBox(width: 8), _buildStyleChip( @@ -551,28 +665,24 @@ class _AppDiyPageState extends State { Icons.auto_awesome, isMd: true, isDark: isDark, - themeColorIdx: themeColorIdx, ), const SizedBox(width: 8), _buildStyleChip( '透明毛玻璃', Icons.blur_on, isDark: isDark, - themeColorIdx: themeColorIdx, ), const SizedBox(width: 8), _buildStyleChip( '沉浸式渐变色', Icons.color_lens, isDark: isDark, - themeColorIdx: themeColorIdx, ), const SizedBox(width: 8), _buildStyleChip( '动态光感效果', Icons.lightbulb_outline, isDark: isDark, - themeColorIdx: themeColorIdx, ), const SizedBox(width: 8), ], @@ -586,8 +696,8 @@ class _AppDiyPageState extends State { decoration: BoxDecoration( gradient: LinearGradient( colors: [ - _themeColors[themeColorIdx].withAlpha(10), - _themeColors[themeColorIdx].withAlpha(5), + _themeController.currentThemeColor.withAlpha(10), + _themeController.currentThemeColor.withAlpha(5), ], ), borderRadius: BorderRadius.circular(8), @@ -597,7 +707,7 @@ class _AppDiyPageState extends State { Icon( Icons.lightbulb_outline, size: 16, - color: _themeColors[themeColorIdx], + color: _themeController.currentThemeColor, ), const SizedBox(width: 8), Expanded( @@ -625,10 +735,9 @@ class _AppDiyPageState extends State { IconData icon, { bool isMd = false, required bool isDark, - required int themeColorIdx, }) { final color = isMd - ? _themeColors[themeColorIdx] + ? _themeController.currentThemeColor : isDark ? Colors.blue[400]! : Colors.blue[600]!; diff --git a/lib/views/responsive_home_page.dart b/lib/views/responsive_home_page.dart index f5c7877..f20f811 100644 --- a/lib/views/responsive_home_page.dart +++ b/lib/views/responsive_home_page.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import '../utils/responsive_layout.dart'; import '../widgets/responsive_widgets.dart'; import '../constants/app_constants.dart'; +import '../services/get/theme_controller.dart'; class ResponsiveHomePage extends StatefulWidget { const ResponsiveHomePage({super.key}); @@ -12,6 +14,7 @@ class ResponsiveHomePage extends StatefulWidget { class _ResponsiveHomePageState extends State { String _layoutMode = AppConstants.gridLayout; + final ThemeController _themeController = Get.find(); @override Widget build(BuildContext context) { @@ -64,18 +67,18 @@ class _ResponsiveHomePageState extends State { text: '网格布局', onPressed: () => _changeLayout(AppConstants.gridLayout), backgroundColor: _layoutMode == AppConstants.gridLayout - ? AppConstants.primaryColor - : Colors.grey[300], - textColor: _layoutMode == AppConstants.gridLayout - ? Colors.white - : Colors.black, + ? _themeController.currentThemeColor + : Colors.grey[300], + textColor: _layoutMode == AppConstants.gridLayout + ? Colors.white + : Colors.black, ), const SizedBox(width: 12), ResponsiveButton( text: '列表布局', onPressed: () => _changeLayout(AppConstants.listLayout), backgroundColor: _layoutMode == AppConstants.listLayout - ? AppConstants.primaryColor + ? _themeController.currentThemeColor : Colors.grey[300], textColor: _layoutMode == AppConstants.listLayout ? Colors.white @@ -133,13 +136,13 @@ class _ResponsiveHomePageState extends State { width: double.infinity, height: ResponsiveLayout.isMobile(context) ? 80 : 120, decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: _themeController.currentThemeColor.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(8), ), child: Icon( Icons.widgets, size: ResponsiveLayout.isMobile(context) ? 32 : 48, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, ), ), const SizedBox(height: 12), @@ -172,13 +175,13 @@ class _ResponsiveHomePageState extends State { width: ResponsiveLayout.isMobile(context) ? 60 : 80, height: ResponsiveLayout.isMobile(context) ? 60 : 80, decoration: BoxDecoration( - color: AppConstants.primaryColor.withValues(alpha: 0.1), + color: _themeController.currentThemeColor.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(8), ), child: Icon( Icons.widgets, size: ResponsiveLayout.isMobile(context) ? 24 : 32, - color: AppConstants.primaryColor, + color: _themeController.currentThemeColor, ), ), const SizedBox(width: 16), diff --git a/lib/widgets/care/care_mode_navigation.dart b/lib/widgets/care/care_mode_navigation.dart new file mode 100644 index 0000000..f4cc950 --- /dev/null +++ b/lib/widgets/care/care_mode_navigation.dart @@ -0,0 +1,219 @@ +/// 时间: 2026-04-02 +/// 功能: 关怀模式底部导航栏 +/// 介绍: 关怀模式下显示的简化底部导航栏,只包含诗词和答题两个入口 +/// 最新变化: 2026-04-02 初始创建 + +import 'dart:ui'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import '../../config/app_config.dart'; +import '../../services/get/theme_controller.dart'; + +class CareModeNavigation extends StatelessWidget { + final int currentIndex; + final Function(int) onTap; + + const CareModeNavigation({ + super.key, + required this.currentIndex, + required this.onTap, + }); + + @override + Widget build(BuildContext context) { + final themeController = Get.find(); + + return Obx(() { + final isDark = themeController.isDarkMode; + final enableBlur = themeController.enableBlurEffect; + final primaryColor = themeController.currentThemeColor; + + return _buildGlassBar(context, isDark, enableBlur, primaryColor); + }); + } + + Widget _buildGlassBar( + BuildContext context, + bool isDark, + bool enableBlur, + Color primaryColor, + ) { + return SafeArea( + top: false, + child: Container( + padding: EdgeInsets.only( + left: AppConfig.liquidGlassHorizontalMargin, + right: AppConfig.liquidGlassHorizontalMargin, + bottom: AppConfig.liquidGlassBottomMargin, + top: 8, + ), + child: Container( + height: AppConfig.liquidGlassHeight, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular( + AppConfig.liquidGlassCornerRadius, + ), + boxShadow: [ + BoxShadow( + color: isDark + ? Colors.black.withValues(alpha: 0.6) + : Colors.black.withValues(alpha: 0.15), + blurRadius: 35, + spreadRadius: -10, + offset: const Offset(0, 12), + ), + ], + ), + child: ClipRRect( + borderRadius: BorderRadius.circular( + AppConfig.liquidGlassCornerRadius, + ), + child: enableBlur + ? BackdropFilter( + filter: ImageFilter.blur( + sigmaX: AppConfig.liquidGlassBlur, + sigmaY: AppConfig.liquidGlassBlur, + ), + child: _buildGlassContent(isDark, primaryColor), + ) + : _buildGlassContent(isDark, primaryColor), + ), + ), + ), + ); + } + + Widget _buildGlassContent(bool isDark, Color primaryColor) { + return Stack( + children: [ + Container( + decoration: BoxDecoration( + color: isDark + ? Colors.black.withValues(alpha: 0.4) + : Colors.white.withValues(alpha: 0.9), + borderRadius: BorderRadius.circular( + AppConfig.liquidGlassCornerRadius, + ), + ), + ), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular( + AppConfig.liquidGlassCornerRadius, + ), + border: Border.all( + color: isDark + ? Colors.white.withValues(alpha: 0.2) + : Colors.black.withValues(alpha: 0.1), + width: 0.6, + ), + ), + ), + _buildNavItems(primaryColor), + ], + ); + } + + Widget _buildNavItems(Color primaryColor) { + final items = [ + _NavItem(Icons.menu_book_rounded, '📖', '诗词', 0), + _NavItem(Icons.psychology_rounded, '🎯', '答题', 1), + ]; + + return Row( + children: List.generate(items.length, (index) { + return Expanded( + child: _buildNavItem( + items[index], + index == currentIndex, + primaryColor, + ), + ); + }), + ); + } + + Widget _buildNavItem(_NavItem item, bool isSelected, Color primaryColor) { + final themeController = Get.find(); + + return Obx(() { + final isDark = themeController.isDarkMode; + final enableAnimation = themeController.enableAnimation; + + return Material( + color: Colors.transparent, + child: InkWell( + onTap: () => onTap(item.index), + splashColor: Colors.transparent, + highlightColor: Colors.transparent, + borderRadius: BorderRadius.circular( + AppConfig.liquidGlassCornerRadius, + ), + child: AnimatedContainer( + duration: enableAnimation + ? const Duration(milliseconds: 250) + : Duration.zero, + curve: Curves.easeOutCubic, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + enableAnimation + ? AnimatedScale( + scale: isSelected ? 1.1 : 1.0, + duration: const Duration(milliseconds: 200), + curve: Curves.easeOutCubic, + child: _buildIcon( + item, + isSelected, + isDark, + primaryColor, + ), + ) + : _buildIcon(item, isSelected, isDark, primaryColor), + const SizedBox(height: 3), + AnimatedDefaultTextStyle( + duration: enableAnimation + ? const Duration(milliseconds: 200) + : Duration.zero, + style: TextStyle( + fontSize: 12, + fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, + color: isSelected + ? primaryColor + : (isDark ? Colors.grey[400] : Colors.grey[600]), + letterSpacing: 0.15, + ), + child: Text(item.label), + ), + ], + ), + ), + ), + ); + }); + } + + Widget _buildIcon( + _NavItem item, + bool isSelected, + bool isDark, + Color primaryColor, + ) { + return Icon( + item.icon, + size: 24, + color: isSelected + ? primaryColor + : (isDark ? Colors.grey[400] : Colors.grey[600]), + ); + } +} + +class _NavItem { + final IconData icon; + final String emoji; + final String label; + final int index; + + _NavItem(this.icon, this.emoji, this.label, this.index); +} diff --git a/lib/widgets/common_widgets.dart b/lib/widgets/common_widgets.dart index 2704feb..16a1bd9 100644 --- a/lib/widgets/common_widgets.dart +++ b/lib/widgets/common_widgets.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import '../constants/app_constants.dart'; +import '../services/get/theme_controller.dart'; // 自定义按钮组件 class CustomButton extends StatelessWidget { @@ -28,13 +30,16 @@ class CustomButton extends StatelessWidget { @override Widget build(BuildContext context) { + final themeController = Get.find(); + final primaryColor = themeController.currentThemeColor; + return SizedBox( width: width, height: height ?? 48, child: ElevatedButton( onPressed: isLoading ? null : onPressed, style: ElevatedButton.styleFrom( - backgroundColor: backgroundColor ?? AppConstants.primaryColor, + backgroundColor: backgroundColor ?? primaryColor, foregroundColor: textColor ?? Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(borderRadius ?? 8), @@ -180,13 +185,16 @@ class LoadingIndicator extends StatelessWidget { @override Widget build(BuildContext context) { + final themeController = Get.find(); + final primaryColor = themeController.currentThemeColor; + return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ CircularProgressIndicator( valueColor: AlwaysStoppedAnimation( - color ?? AppConstants.primaryColor, + color ?? primaryColor, ), ), if (message != null) ...[ diff --git a/lib/widgets/main_navigation.dart b/lib/widgets/main_navigation.dart index 208c95e..ce1cfe0 100644 --- a/lib/widgets/main_navigation.dart +++ b/lib/widgets/main_navigation.dart @@ -1,15 +1,18 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import '../constants/app_constants.dart'; import '../views/home/home_page.dart'; import '../views/discover_page.dart'; import '../views/favorites_page.dart'; import '../views/profile/profile_page.dart'; +import '../views/profile/level/poetry.dart'; +import '../views/home/care/care_poetry_page.dart'; import '../services/get/main_navigation_controller.dart'; import '../services/get/profile_controller.dart'; import '../services/get/theme_controller.dart'; import '../services/get/tap_liquid_glass_controller.dart'; +import '../services/get/care_controller.dart'; import 'tap-liquid-glass.dart'; +import 'care/care_mode_navigation.dart'; /// 时间: 2025-03-21 /// 功能: 主导航页面,包含底部导航栏和4个主要页面 @@ -24,9 +27,11 @@ class MainNavigation extends StatelessWidget { // 初始化导航控制器(只初始化一次) Get.lazyPut(() => MainNavigationController()); Get.lazyPut(() => TapLiquidGlassController()); + Get.lazyPut(() => CareController()); final controller = Get.find(); final themeController = Get.find(); final glassController = Get.find(); + final careController = Get.find(); final List pages = [ HomePage(), @@ -35,25 +40,27 @@ class MainNavigation extends StatelessWidget { const ProfilePage(), ]; + final primaryColor = themeController.currentThemeColor; + final List bottomNavItems = [ - const BottomNavigationBarItem( - icon: Icon(Icons.home), - activeIcon: Icon(Icons.home, color: AppConstants.primaryColor), + BottomNavigationBarItem( + icon: const Icon(Icons.home), + activeIcon: Icon(Icons.home, color: primaryColor), label: '主页', ), - const BottomNavigationBarItem( - icon: Icon(Icons.explore), - activeIcon: Icon(Icons.explore, color: AppConstants.primaryColor), + BottomNavigationBarItem( + icon: const Icon(Icons.explore), + activeIcon: Icon(Icons.explore, color: primaryColor), label: '发现', ), - const BottomNavigationBarItem( - icon: Icon(Icons.favorite_border), - activeIcon: Icon(Icons.favorite, color: AppConstants.primaryColor), + BottomNavigationBarItem( + icon: const Icon(Icons.favorite_border), + activeIcon: Icon(Icons.favorite, color: primaryColor), label: '收藏', ), - const BottomNavigationBarItem( - icon: Icon(Icons.person_outline), - activeIcon: Icon(Icons.person, color: AppConstants.primaryColor), + BottomNavigationBarItem( + icon: const Icon(Icons.person_outline), + activeIcon: Icon(Icons.person, color: primaryColor), label: '个人', ), ]; @@ -61,11 +68,23 @@ class MainNavigation extends StatelessWidget { return Obx(() { final isDark = themeController.isDarkMode; final useGlass = glassController.isEnabled; + final isCareMode = careController.isCareModeEnabled; + + // 关怀模式开启时,使用关怀模式的导航栏 + if (isCareMode) { + return Scaffold(body: _buildCareModeBody(careController)); + } return Scaffold( body: useGlass ? _buildGlassBody(controller, pages) - : _buildClassicBody(controller, pages, isDark, bottomNavItems), + : _buildClassicBody( + controller, + pages, + isDark, + bottomNavItems, + primaryColor, + ), ); }); } @@ -79,10 +98,7 @@ class MainNavigation extends StatelessWidget { return Stack( children: [ // 页面内容 - 延伸到屏幕底部 - IndexedStack( - index: controller.currentIndex.value, - children: pages, - ), + IndexedStack(index: controller.currentIndex.value, children: pages), // 悬浮的液态玻璃导航栏 Positioned( left: 0, @@ -109,6 +125,7 @@ class MainNavigation extends StatelessWidget { List pages, bool isDark, List items, + Color primaryColor, ) { return Column( children: [ @@ -143,7 +160,7 @@ class MainNavigation extends StatelessWidget { } }, type: BottomNavigationBarType.fixed, - selectedItemColor: AppConstants.primaryColor, + selectedItemColor: primaryColor, unselectedItemColor: isDark ? Colors.grey[400] : Colors.grey[600], backgroundColor: isDark ? const Color(0xFF2A2A2A) : Colors.white, elevation: 0, @@ -156,4 +173,34 @@ class MainNavigation extends StatelessWidget { ], ); } + + /// 构建关怀模式主体 + /// 使用 Stack 布局,让导航栏悬浮在页面内容上方 + Widget _buildCareModeBody(CareController careController) { + return Obx(() { + final carePages = [const CarePoetryPage(), const PoetryLevelPage()]; + + return Stack( + children: [ + // 页面内容 - 延伸到屏幕底部 + IndexedStack( + index: careController.careNavigationIndex, + children: carePages, + ), + // 悬浮的关怀模式导航栏 + Positioned( + left: 0, + right: 0, + bottom: 0, + child: CareModeNavigation( + currentIndex: careController.careNavigationIndex, + onTap: (index) { + careController.switchCareNavigation(index); + }, + ), + ), + ], + ); + }); + } } diff --git a/lib/widgets/responsive_widgets.dart b/lib/widgets/responsive_widgets.dart index c31e367..272af09 100644 --- a/lib/widgets/responsive_widgets.dart +++ b/lib/widgets/responsive_widgets.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import '../utils/responsive_layout.dart'; import '../constants/app_constants.dart'; +import '../services/get/theme_controller.dart'; class ResponsiveButton extends StatelessWidget { final String text; @@ -25,6 +27,8 @@ class ResponsiveButton extends StatelessWidget { @override Widget build(BuildContext context) { final buttonSize = size ?? (ResponsiveLayout.isMobile(context) ? ButtonSize.small : ButtonSize.medium); + final themeController = Get.find(); + final primaryColor = themeController.currentThemeColor; return SizedBox( width: ResponsiveLayout.isMobile(context) ? double.infinity : null, @@ -32,7 +36,7 @@ class ResponsiveButton extends StatelessWidget { child: ElevatedButton( onPressed: isLoading ? null : onPressed, style: ElevatedButton.styleFrom( - backgroundColor: backgroundColor ?? AppConstants.primaryColor, + backgroundColor: backgroundColor ?? primaryColor, foregroundColor: textColor ?? Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(_getBorderRadius(buttonSize)), diff --git a/lib/widgets/tabbed_nav_app_bar.dart b/lib/widgets/tabbed_nav_app_bar.dart index fb715c9..5edcb85 100644 --- a/lib/widgets/tabbed_nav_app_bar.dart +++ b/lib/widgets/tabbed_nav_app_bar.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:get/get.dart'; import '../constants/app_constants.dart'; +import '../services/get/theme_controller.dart'; /// 时间: 2026-03-22 /// 功能: 主导航内「标题 + Tab」共用 AppBar 构造 @@ -23,6 +25,8 @@ class TabbedNavAppBar { Color? foregroundColor, }) { final isDark = backgroundColor != null && backgroundColor != Colors.white; + final themeController = Get.find(); + final primaryColor = themeController.currentThemeColor; return AppBar( title: Text( @@ -55,10 +59,10 @@ class TabbedNavAppBar { dividerHeight: 0, dividerColor: Colors.transparent, tabs: tabLabels.map((String e) => Tab(text: e)).toList(), - labelColor: AppConstants.primaryColor, + labelColor: primaryColor, unselectedLabelColor: isDark ? Colors.grey[400] : Colors.grey[600], indicator: UnderlineTabIndicator( - borderSide: BorderSide(color: AppConstants.primaryColor, width: 3), + borderSide: BorderSide(color: primaryColor, width: 3), ), labelStyle: const TextStyle(fontWeight: FontWeight.bold), ), diff --git a/lib/widgets/tap-liquid-glass.dart b/lib/widgets/tap-liquid-glass.dart index 63a075a..99f7ab0 100644 --- a/lib/widgets/tap-liquid-glass.dart +++ b/lib/widgets/tap-liquid-glass.dart @@ -178,7 +178,7 @@ class TapLiquidGlassNavigation extends StatelessWidget { fontSize: 12, fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400, color: isSelected - ? AppConstants.primaryColor + ? themeController.currentThemeColor : (isDark ? Colors.grey[400] : Colors.grey[600]), letterSpacing: 0.15, ), @@ -193,11 +193,13 @@ class TapLiquidGlassNavigation extends StatelessWidget { } Widget _buildIcon(_NavItem item, bool isSelected, bool isDark) { + final themeController = Get.find(); + return Icon( item.icon, size: 24, color: isSelected - ? AppConstants.primaryColor + ? themeController.currentThemeColor : (isDark ? Colors.grey[400] : Colors.grey[600]), ); } diff --git a/pubspec.lock b/pubspec.lock index 8f96d0c..9ac6ebf 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -440,6 +440,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "7.0.2" + pinyin: + dependency: "direct main" + description: + name: pinyin + sha256: "240f271a3c71af20c8d2757756b5ee8e9d79a955d37abad4b3568fd406b22411" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.3.0" platform: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 3768436..f76f46b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,8 +37,9 @@ dependencies: get: git: url: https://gitcode.com/openharmony-sig/fluttertpc_get + pinyin: ^3.3.0 + - dev_dependencies: flutter_test: sdk: flutter diff --git a/update_android_icons.py b/update_android_icons.py new file mode 100644 index 0000000..2f5eb24 --- /dev/null +++ b/update_android_icons.py @@ -0,0 +1,40 @@ +from PIL import Image +import os + +# 新的图片路径 +new_image_path = r"e:\project\flutter\f3\flutter_application_2\assets\IMG_20260402_172628.png" + +# 安卓端图标目录 +android_res_dir = r"e:\project\flutter\f3\flutter_application_2\android\app\src\main\res" + +# 安卓端图标尺寸配置 (density: (width, height)) +android_sizes = { + "mdpi": (48, 48), + "hdpi": (72, 72), + "xhdpi": (144, 144), + "xxhdpi": (96, 96), + "xxxhdpi": (192, 192), +} + +try: + # 打开新图片 + with Image.open(new_image_path) as img: + print(f"新图片尺寸: {img.size}") + + # 为每个密度生成图标 + for density, size in android_sizes.items(): + # 调整尺寸 + resized_img = img.resize(size, Image.Resampling.LANCZOS) + + # 构建输出路径 + output_dir = os.path.join(android_res_dir, f"mipmap-{density}") + os.makedirs(output_dir, exist_ok=True) + + output_path = os.path.join(output_dir, "ic_launcher.png") + resized_img.save(output_path) + print(f"已保存 {density} ({size[0]}x{size[1]}) 图标到: {output_path}") + + print("\n安卓端所有图标更新完成!") + +except Exception as e: + print(f"处理图片时出错: {e}")