From 874e21708af5d8f9bad3aeb7bb6709aeabee87bb Mon Sep 17 00:00:00 2001 From: DelLevin-Home Date: Sat, 7 Mar 2026 11:55:27 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=A4=87=E4=BB=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QUICKSTART.md | 251 -------------------------- README.md | 106 +---------- lib/pages/backup_page.dart | 25 +-- lib/pages/book_detail_page.dart | 21 +-- lib/pages/book_excerpt_form_page.dart | 9 +- lib/pages/book_excerpts_page.dart | 9 +- lib/pages/book_form_page.dart | 12 +- lib/pages/book_review_form_page.dart | 8 +- lib/pages/book_reviews_page.dart | 9 +- lib/pages/movie_detail_page.dart | 21 +-- lib/pages/movie_form_page.dart | 12 +- lib/pages/movie_form_page_new.dart | 16 +- lib/pages/movie_posters_page.dart | 4 +- lib/pages/movie_review_form_page.dart | 8 +- lib/pages/movie_reviews_page.dart | 5 +- lib/pages/note_detail_page.dart | 5 +- lib/pages/note_form_page.dart | 12 +- lib/pages/profile_page.dart | 9 +- lib/pages/recycle_bin_page.dart | 29 +-- lib/pages/search_page.dart | 5 +- lib/widgets/custom_drawer.dart | 9 +- 21 files changed, 73 insertions(+), 512 deletions(-) delete mode 100644 QUICKSTART.md diff --git a/QUICKSTART.md b/QUICKSTART.md deleted file mode 100644 index 22bc3a5..0000000 --- a/QUICKSTART.md +++ /dev/null @@ -1,251 +0,0 @@ -# MookNote 快速入门指南 - -## 第一步:安装 Flutter 开发环境 - -### Windows 系统详细步骤 - -#### 1. 下载 Flutter SDK -访问:https://docs.flutter.dev/get-started/install/windows -- 点击 "Download Flutter SDK" -- 下载完成后解压到 `C:\src\flutter` - -#### 2. 添加环境变量 -``` -1. 右键"此电脑" → "属性" → "高级系统设置" -2. 点击"环境变量" -3. 在"系统变量"中找到 "Path",点击"编辑" -4. 点击"新建",添加:C:\src\flutter\bin -5. 确定保存 -``` - -#### 3. 验证安装 - -打开命令提示符(cmd)或 PowerShell: -```bash -flutter --version -flutter doctor -``` - -#### 4. 安装 Android Studio - -- 下载地址:https://developer.android.com/studio -- 安装完成后打开 Android Studio -- 配置 Android SDK: - - File → Settings → Appearance & Behavior → System Settings → Android SDK - - 选择 "SDK Platforms" 标签 - - 勾选 "Android 13.0 (API 33)" 或更高版本 - - 选择 "SDK Tools" 标签 - - 勾选 "Android SDK Build-Tools" 和 "Android Emulator" - - 点击 Apply 开始安装 - -#### 5. 接受 Android 许可证 -```bash -flutter doctor --android-licenses -``` -按提示输入 `y` 接受所有许可证 - -#### 6. 再次运行 flutter doctor -```bash -flutter doctor -``` -确保看到类似以下输出: -``` -[✓] Flutter (Channel stable, 3.x.x, on Microsoft Windows) -[✓] Android toolchain - develop for Android devices -[✓] Android Studio -[✓] Connected device -``` - -## 第二步:运行 MookNote 项目 - -### 1. 进入项目目录 -```bash -cd d:\UserData\Desktop\my_proj\mooknote -``` - -### 2. 安装依赖包 -```bash -flutter pub get -``` - -### 3. 准备设备 -**选项 A:使用真机** -``` -1. 手机开启"开发者选项" - - 设置 → 关于手机 → 连续点击"版本号"7 次 -2. 开启"USB 调试" - - 设置 → 开发者选项 → USB 调试 -3. 用 USB 连接电脑 -4. 手机上允许 USB 调试授权 -``` - -**选项 B:使用模拟器** -``` -1. Android Studio → Tools → Device Manager -2. Click "Create device" -3. 选择设备型号(如 Pixel 6) -4. 下载并选择系统镜像(推荐 API 33) -5. 完成创建后点击启动按钮 -``` - -### 4. 运行应用 -```bash -flutter run -``` - -或者在 Android Studio 中: -- File → Open → 选择 mooknote 文件夹 -- 点击顶部工具栏的运行按钮(绿色三角形) - -## 第三步:理解代码结构 - -### 核心文件说明 - -#### 1. 入口文件 - `lib/main.dart` -```dart -void main() { - runApp(const MyApp()); -} -``` -应用的起点,配置主题和路由 - -#### 2. 主页面 - `lib/pages/home_page.dart` -包含: -- 顶部 AppBar(菜单按钮 + 标题) -- 三个标签页切换(观影/阅读/笔记) -- 主体内容区域 - -#### 3. 状态管理 - `lib/providers/app_provider.dart` -管理全局状态: -- 当前选中的标签页 -- 当前选中的状态筛选 -- 侧边菜单开关 - -#### 4. 数据模型 - `lib/models/data_models.dart` -定义数据结构: -- `Movie` - 电影数据 -- `Book` - 书籍数据 -- `Note` - 笔记数据 - -### Widget 组件层次 -``` -MyApp -└── HomePage (主页面) - ├── CustomDrawer (侧边菜单) - │ └── 热力图组件 - ├── AppBar (顶部栏) - ├── TabBar (标签栏) - │ ├── 观影 - │ ├── 阅读 - │ └── 笔记 - ├── TabContent (标签内容) - │ ├── MovieTabPage - │ │ ├── MovieStatusBar (状态栏) - │ │ └── MovieListItem (列表项) - │ ├── BookTabPage - │ │ ├── BookStatusBar (状态栏) - │ │ └── BookListItem (列表项) - │ └── NoteTabPage - │ └── NoteListItem (列表项) - └── CustomBottomNavBar (底部导航) -``` - -## 第四步:修改和定制 - -### 修改应用名称 -编辑 `pubspec.yaml`: -```yaml -name: mooknote # 包名 -``` - -编辑 `android/app/src/main/AndroidManifest.xml`: -```xml -android:label="MookNote" -``` - -### 修改主题颜色 -编辑 `lib/utils/app_theme.dart`: -```dart -static const Color primaryColor = Color(0xFF6200EE); // 主色调 -``` - -### 添加示例数据 -编辑对应的 page 文件,例如 `lib/pages/movie_tab_page.dart`: -```dart -List _getSampleMovies(int statusIndex) { - // 在这里添加你的电影数据 -} -``` - -## 第五步:构建 APK - -### 开发版本 -```bash -flutter build apk --debug -``` - -### 发布版本 -```bash -flutter build apk --release -``` - -生成的 APK 位置: -``` -build/app/outputs/flutter-apk/app-release.apk -``` - -## 常见问题解决 - -### Q1: flutter pub get 失败 -```bash -# 清除缓存 -flutter clean -flutter pub cache repair -flutter pub get -``` - -### Q2: 无法识别设备 -```bash -# 查看设备列表 -flutter devices - -# 如果没有设备,检查: -# 1. USB 线是否连接好 -# 2. 手机 USB 调试是否开启 -# 3. 是否安装了手机驱动 -``` - -### Q3: 热重载不工作 -按 `R` 进行热重载,按 `r` 完全重启 -如果都不行,停止应用重新运行 - -### Q4: 中文乱码 -确保所有文件使用 UTF-8 编码 - -## 下一步学习建议 - -### 1. 学习 Dart 基础语法(1-2 天) -- 变量和类型 -- 函数 -- 类和对象 -- 异步编程(async/await) - -### 2. 学习 Flutter 基础(3-5 天) -- Widget 概念 -- StatelessWidget vs StatefulWidget -- 布局组件(Row, Column, Container 等) -- 列表(ListView) - -### 3. 实践项目功能 -- 实现添加功能表单 -- 集成 SQLite 数据库 -- 实现搜索功能 -- 完善详情页 - -### 4. 参考资源 -- [Dart 语言中文文档](https://dart.cn/) -- [Flutter 实战电子书](https://book.flutterchina.club/) -- [B 站 Flutter 教程](https://search.bilibili.com/all?keyword=flutter 教程) - ---- -祝你开发顺利!有问题随时询问。 diff --git a/README.md b/README.md index 3f29529..3ea2df8 100644 --- a/README.md +++ b/README.md @@ -74,18 +74,6 @@ MookNote 是一款用于记录观影、阅读和笔记的 Android 应用,使 flutter doctor --android-licenses ``` - - -```bash -$env:HTTP_PROXY="http://127.0.0.1:10808" -$env:HTTPS_PROXY="http://127.0.0.1:10808" -flutter create --platforms android . -``` - - - - - ## 运行项目 ### 1. 克隆/复制项目后,进入项目目录 @@ -97,9 +85,13 @@ cd mooknote ```bash flutter pub get +# 如果失败可以先添加代理再进行get +$env:HTTP_PROXY="http://127.0.0.1:10808" +$env:HTTPS_PROXY="http://127.0.0.1:10808" ``` ### 3. 连接设备或启动模拟器 + - 连接 Android 真机(需开启 USB 调试) - 或启动 Android 模拟器 @@ -112,43 +104,6 @@ flutter run - 打开项目 - 点击运行按钮 (Run) -## 项目结构 - -``` -mooknote/ -├── android/ # Android 平台配置 -│ └── app/ -│ └── src/main/ -│ ├── AndroidManifest.xml -│ └── ... -├── lib/ # Dart 源代码 -│ ├── main.dart # 应用入口 -│ ├── pages/ # 页面组件 -│ │ ├── home_page.dart # 主页面 -│ │ ├── movie_tab_page.dart # 观影标签页 -│ │ ├── book_tab_page.dart # 阅读标签页 -│ │ └── note_tab_page.dart # 笔记标签页 -│ ├── widgets/ # 可复用组件 -│ │ ├── custom_drawer.dart # 侧边菜单 -│ │ ├── bottom_nav_bar.dart # 底部导航 -│ │ ├── movie_status_bar.dart # 观影状态栏 -│ │ ├── movie_list_item.dart # 观影列表项 -│ │ ├── book_status_bar.dart # 书籍状态栏 -│ │ ├── book_list_item.dart # 书籍列表项 -│ │ └── note_list_item.dart # 笔记列表项 -│ ├── models/ # 数据模型 -│ │ └── data_models.dart # Movie, Book, Note 模型 -│ ├── providers/ # 状态管理 -│ │ └── app_provider.dart # 全局状态管理 -│ └── utils/ # 工具类 -│ └── app_theme.dart # 主题配置 -├── assets/ # 资源文件 -│ └── images/ # 图片资源 -├── fonts/ # 字体文件 -├── pubspec.yaml # 项目配置文件 -└── README.md # 本文件 -``` - ## 技术栈 - **Flutter**: 跨平台移动应用框架 @@ -162,58 +117,17 @@ mooknote/ - [x] 集成 SQLite 数据库(sqflite 包) - [x] 实现本地数据持久化 -- [ ] 数据备份与恢复 +- [x] 数据备份与恢复 ### 功能增强 - [x] 添加/编辑表单页面 -- [ ] 详情页完整实现 -- [ ] 搜索功能 -- [ ] 统计图表页面 -- [ ] 回收站功能 -- [ ] 设置页面 - -### 用户体验 -- [ ] 加载动画 -- [ ] 下拉刷新 -- [ ] 无限滚动加载 -- [ ] 深色模式优化 +- [x] 详情页完整实现 +- [x] 搜索功能 +- [x] 统计图表页面 +- [x] 回收站功能 ### 高级功能 -- [ ] 导出功能(JSON/CSV) +- [x] 导出功能(JSON) - [ ] 云同步 -- [ ] 桌面小组件 - -## 常见问题 - -### Q: flutter doctor 显示 Android license status unknown -A: 运行 `flutter doctor --android-licenses` 接受许可证 - -### Q: 模拟器无法启动 -A: 确保在 BIOS 中启用了虚拟化技术(VT-x/AMD-V) - -### Q: 热重载不生效 -A: 某些代码更改需要完全重启应用(如 main() 函数修改) - -## 开发建议 - -### 对于有 Vue 经验的你 -Flutter 的很多概念与 Vue 相似: -- **Widget** ≈ Vue 组件 -- **StatefulWidget** ≈ 带数据的 Vue 组件 -- **setState()** ≈ this.$forceUpdate() + 数据更新 -- **Provider** ≈ Vuex/Pinia -- **pubspec.yaml** ≈ package.json - -### 学习资源 -- [Flutter 官方文档](https://docs.flutter.dev/) -- [Dart 语言指南](https://dart.dev/guides) -- [Flutter 中文社区](https://flutterchina.club/) - -## 许可证 -MIT License - ---- -**作者**: 你的昵称 -**创建时间**: 2024-03-04 diff --git a/lib/pages/backup_page.dart b/lib/pages/backup_page.dart index ecb1c41..05c411a 100644 --- a/lib/pages/backup_page.dart +++ b/lib/pages/backup_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../utils/backup_service.dart'; +import '../utils/toast_util.dart'; /// 数据备份页面 class BackupPage extends StatefulWidget { @@ -185,9 +186,7 @@ class _BackupPageState extends State { if (!mounted) return; if (result.cancelled) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('已取消导出')), - ); + ToastUtil.show(context, '已取消导出'); } else if (result.success) { // 显示导出成功信息 showDialog( @@ -214,15 +213,11 @@ class _BackupPageState extends State { ), ); } else { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(result.errorMessage ?? '导出失败')), - ); + ToastUtil.show(context, result.errorMessage ?? '导出失败'); } } catch (e) { if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('导出失败: $e')), - ); + ToastUtil.show(context, '导出失败: $e'); } } finally { if (mounted) { @@ -267,9 +262,7 @@ class _BackupPageState extends State { if (!mounted) return; if (result.cancelled) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('已取消导入')), - ); + ToastUtil.show(context, '已取消导入'); } else if (result.success) { // 刷新数据 await context.read().loadMovies(); @@ -293,15 +286,11 @@ class _BackupPageState extends State { ), ); } else { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(result.errorMessage ?? '导入失败')), - ); + ToastUtil.show(context, result.errorMessage ?? '导入失败'); } } catch (e) { if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('导入失败: $e')), - ); + ToastUtil.show(context, '导入失败: $e'); } } finally { if (mounted) { diff --git a/lib/pages/book_detail_page.dart b/lib/pages/book_detail_page.dart index cfc53b7..4926218 100644 --- a/lib/pages/book_detail_page.dart +++ b/lib/pages/book_detail_page.dart @@ -5,6 +5,7 @@ import 'package:share_plus/share_plus.dart'; import 'package:cross_file/cross_file.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; +import '../utils/toast_util.dart'; import 'book_reviews_page.dart'; import 'book_excerpts_page.dart'; @@ -657,9 +658,7 @@ class _BookDetailPageState extends State { if (!mounted) return; Navigator.pop(context); Navigator.pop(context); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('已删除')), - ); + ToastUtil.show(context, '已删除'); }, child: const Text('删除', style: TextStyle(color: Colors.red)), ), @@ -692,9 +691,7 @@ class _BookDetailPageState extends State { ); await context.read().updateBook(updatedBook); if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('封面已清空')), - ); + ToastUtil.show(context, '封面已清空'); } }, child: const Text('清空', style: TextStyle(color: Colors.red)), @@ -707,18 +704,14 @@ class _BookDetailPageState extends State { /// 下载封面到本地 Future _downloadCover(Book book) async { if (book.coverPath == null || book.coverPath!.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('没有可下载的封面')), - ); + ToastUtil.show(context, '没有可下载的封面'); return; } try { final sourceFile = File(book.coverPath!); if (!await sourceFile.exists()) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('封面文件不存在')), - ); + ToastUtil.show(context, '封面文件不存在'); return; } @@ -738,9 +731,7 @@ class _BookDetailPageState extends State { text: '下载自 MookNote', ); } catch (e) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('下载失败: $e')), - ); + ToastUtil.show(context, '下载失败: $e'); } } } diff --git a/lib/pages/book_excerpt_form_page.dart b/lib/pages/book_excerpt_form_page.dart index 2dc64a3..c380dcd 100644 --- a/lib/pages/book_excerpt_form_page.dart +++ b/lib/pages/book_excerpt_form_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; +import '../utils/toast_util.dart'; import 'package:uuid/uuid.dart'; /// 摘抄表单页面 - 新增/编辑摘抄 @@ -171,15 +172,11 @@ class _BookExcerptFormPageState extends State { if (mounted) { Navigator.pop(context); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(_isEditing ? '摘抄已更新' : '摘抄已添加')), - ); + ToastUtil.show(context, _isEditing ? '摘抄已更新' : '摘抄已添加'); } } catch (e) { if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('保存失败: $e')), - ); + ToastUtil.show(context, '保存失败: $e'); } } finally { if (mounted) { diff --git a/lib/pages/book_excerpts_page.dart b/lib/pages/book_excerpts_page.dart index 17db5d8..eb48f59 100644 --- a/lib/pages/book_excerpts_page.dart +++ b/lib/pages/book_excerpts_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; +import '../utils/toast_util.dart'; import 'book_excerpt_form_page.dart'; /// 书籍摘抄列表页面 @@ -34,9 +35,7 @@ class _BookExcerptsPageState extends State { }); } catch (e) { setState(() => _isLoading = false); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('加载失败: $e')), - ); + ToastUtil.show(context, '加载失败: $e'); } } @@ -287,9 +286,7 @@ class _BookExcerptsPageState extends State { await context.read().removeBookExcerpt(excerpt.id); Navigator.pop(context); _loadExcerpts(); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('已删除')), - ); + ToastUtil.show(context, '已删除'); }, child: const Text('删除', style: TextStyle(color: Colors.red)), ), diff --git a/lib/pages/book_form_page.dart b/lib/pages/book_form_page.dart index 6700e0f..7de4413 100644 --- a/lib/pages/book_form_page.dart +++ b/lib/pages/book_form_page.dart @@ -6,6 +6,7 @@ import 'package:path/path.dart' as path; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; +import '../utils/toast_util.dart'; /// 添加/编辑书籍页面 - 紧凑双行布局设计 class BookFormPage extends StatefulWidget { @@ -663,9 +664,7 @@ class _BookFormPageState extends State { } } catch (e) { if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('选择封面失败: $e')), - ); + ToastUtil.show(context, '选择封面失败: $e'); } } } @@ -718,12 +717,7 @@ class _BookFormPageState extends State { if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(widget.book == null ? '添加成功' : '更新成功'), - behavior: SnackBarBehavior.floating, - ), - ); + ToastUtil.show(context, widget.book == null ? '添加成功' : '更新成功'); Navigator.pop(context); } diff --git a/lib/pages/book_review_form_page.dart b/lib/pages/book_review_form_page.dart index c678170..5ec1f86 100644 --- a/lib/pages/book_review_form_page.dart +++ b/lib/pages/book_review_form_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; +import '../utils/toast_util.dart'; import 'package:uuid/uuid.dart'; /// 添加/编辑书评页面 - 极简设计 @@ -253,12 +254,7 @@ class _BookReviewFormPageState extends State { if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(widget.review == null ? '添加成功' : '更新成功'), - behavior: SnackBarBehavior.floating, - ), - ); + ToastUtil.show(context, widget.review == null ? '添加成功' : '更新成功'); Navigator.pop(context); } diff --git a/lib/pages/book_reviews_page.dart b/lib/pages/book_reviews_page.dart index 9f905ff..30c685a 100644 --- a/lib/pages/book_reviews_page.dart +++ b/lib/pages/book_reviews_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; +import '../utils/toast_util.dart'; import 'book_review_form_page.dart'; /// 书籍书评列表页面 @@ -34,9 +35,7 @@ class _BookReviewsPageState extends State { }); } catch (e) { setState(() => _isLoading = false); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('加载失败: $e')), - ); + ToastUtil.show(context, '加载失败: $e'); } } @@ -257,9 +256,7 @@ class _BookReviewsPageState extends State { await context.read().removeBookReview(review.id); Navigator.pop(context); _loadReviews(); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('已删除')), - ); + ToastUtil.show(context, '已删除'); }, child: const Text('删除', style: TextStyle(color: Colors.red)), ), diff --git a/lib/pages/movie_detail_page.dart b/lib/pages/movie_detail_page.dart index ca91edc..8ce9232 100644 --- a/lib/pages/movie_detail_page.dart +++ b/lib/pages/movie_detail_page.dart @@ -8,6 +8,7 @@ import 'package:cross_file/cross_file.dart'; import 'package:permission_handler/permission_handler.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; +import '../utils/toast_util.dart'; import 'movie_reviews_page.dart'; import 'movie_posters_page.dart'; @@ -212,9 +213,7 @@ class _MovieDetailPageState extends State { ); await context.read().updateMovie(updatedMovie); if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('海报已清空')), - ); + ToastUtil.show(context, '海报已清空'); } }, child: const Text('清空', style: TextStyle(color: Colors.red)), @@ -768,9 +767,7 @@ class _MovieDetailPageState extends State { if (!mounted) return; Navigator.pop(context); Navigator.pop(context); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('已删除')), - ); + ToastUtil.show(context, '已删除'); }, child: const Text('删除', style: TextStyle(color: Colors.red)), ), @@ -782,18 +779,14 @@ class _MovieDetailPageState extends State { /// 下载海报到本地 Future _downloadPoster(Movie movie) async { if (movie.posterPath == null || movie.posterPath!.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('没有可下载的海报')), - ); + ToastUtil.show(context, '没有可下载的海报'); return; } try { final sourceFile = File(movie.posterPath!); if (!await sourceFile.exists()) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('海报文件不存在')), - ); + ToastUtil.show(context, '海报文件不存在'); return; } @@ -813,9 +806,7 @@ class _MovieDetailPageState extends State { text: '下载自 MookNote', ); } catch (e) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('下载失败: $e')), - ); + ToastUtil.show(context, '下载失败: $e'); } } diff --git a/lib/pages/movie_form_page.dart b/lib/pages/movie_form_page.dart index 8e90ffb..719cfee 100644 --- a/lib/pages/movie_form_page.dart +++ b/lib/pages/movie_form_page.dart @@ -6,6 +6,7 @@ import 'package:path/path.dart' as path; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; +import '../utils/toast_util.dart'; /// 添加/编辑影视页面 - 紧凑双行布局设计 class MovieFormPage extends StatefulWidget { @@ -705,9 +706,7 @@ class _MovieFormPageState extends State { } } catch (e) { if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('选择海报失败: $e')), - ); + ToastUtil.show(context, '选择海报失败: $e'); } } } @@ -788,12 +787,7 @@ class _MovieFormPageState extends State { if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(widget.movie == null ? '添加成功' : '更新成功'), - behavior: SnackBarBehavior.floating, - ), - ); + ToastUtil.show(context, widget.movie == null ? '添加成功' : '更新成功'); Navigator.pop(context); } diff --git a/lib/pages/movie_form_page_new.dart b/lib/pages/movie_form_page_new.dart index 844d6e7..d8e5f49 100644 --- a/lib/pages/movie_form_page_new.dart +++ b/lib/pages/movie_form_page_new.dart @@ -6,6 +6,7 @@ import 'package:provider/provider.dart'; import 'package:uuid/uuid.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; +import '../utils/toast_util.dart'; /// 添加/编辑影视记录页面(Typecho 风格) class MovieFormPage extends StatefulWidget { @@ -527,23 +528,12 @@ class _MovieFormPageState extends State { if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(widget.movie == null ? '添加成功' : '更新成功'), - behavior: SnackBarBehavior.floating, - ), - ); + ToastUtil.show(context, widget.movie == null ? '添加成功' : '更新成功'); Navigator.pop(context); } catch (e) { if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('保存失败:$e'), - behavior: SnackBarBehavior.floating, - backgroundColor: Colors.red, - ), - ); + ToastUtil.show(context, '保存失败:$e'); } finally { if (mounted) { setState(() { diff --git a/lib/pages/movie_posters_page.dart b/lib/pages/movie_posters_page.dart index 0a8df62..f690294 100644 --- a/lib/pages/movie_posters_page.dart +++ b/lib/pages/movie_posters_page.dart @@ -248,9 +248,7 @@ class _MoviePostersPageState extends State { } } catch (e) { if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('添加海报失败: $e')), - ); + ToastUtil.show(context, '添加海报失败: $e'); } } } diff --git a/lib/pages/movie_review_form_page.dart b/lib/pages/movie_review_form_page.dart index cff87e2..6bc58ed 100644 --- a/lib/pages/movie_review_form_page.dart +++ b/lib/pages/movie_review_form_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; +import '../utils/toast_util.dart'; /// 添加/编辑影评页面 - 极简设计 class MovieReviewFormPage extends StatefulWidget { @@ -251,12 +252,7 @@ class _MovieReviewFormPageState extends State { if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(widget.review == null ? '添加成功' : '更新成功'), - behavior: SnackBarBehavior.floating, - ), - ); + ToastUtil.show(context, widget.review == null ? '添加成功' : '更新成功'); Navigator.pop(context); } diff --git a/lib/pages/movie_reviews_page.dart b/lib/pages/movie_reviews_page.dart index 647109c..f09292d 100644 --- a/lib/pages/movie_reviews_page.dart +++ b/lib/pages/movie_reviews_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; +import '../utils/toast_util.dart'; import 'movie_review_form_page.dart'; /// 影视影评列表页面 @@ -250,9 +251,7 @@ class _MovieReviewsPageState extends State { await context.read().removeMovieReview(review.id); Navigator.pop(context); _loadReviews(); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('已删除')), - ); + ToastUtil.show(context, '已删除'); }, child: const Text('删除', style: TextStyle(color: Colors.red)), ), diff --git a/lib/pages/note_detail_page.dart b/lib/pages/note_detail_page.dart index 21621b7..b96a722 100644 --- a/lib/pages/note_detail_page.dart +++ b/lib/pages/note_detail_page.dart @@ -3,6 +3,7 @@ import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; +import '../utils/toast_util.dart'; /// 笔记详情页 - 极简主义设计 class NoteDetailPage extends StatefulWidget { @@ -255,9 +256,7 @@ class _NoteDetailPageState extends State { if (!mounted) return; Navigator.pop(context); Navigator.pop(context); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('已删除')), - ); + ToastUtil.show(context, '已删除'); }, child: const Text('删除', style: TextStyle(color: Colors.red)), ), diff --git a/lib/pages/note_form_page.dart b/lib/pages/note_form_page.dart index 1d91bda..9a09c2e 100644 --- a/lib/pages/note_form_page.dart +++ b/lib/pages/note_form_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; +import '../utils/toast_util.dart'; /// 添加/编辑笔记页面 - 极简书写界面 class NoteFormPage extends StatefulWidget { @@ -331,9 +332,7 @@ class _NoteFormPageState extends State { final content = _contentController.text.trim(); if (content.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('笔记内容不能为空')), - ); + ToastUtil.show(context, '笔记内容不能为空'); return; } @@ -363,12 +362,7 @@ class _NoteFormPageState extends State { if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(_isEditing ? '保存成功' : '添加成功'), - behavior: SnackBarBehavior.floating, - ), - ); + ToastUtil.show(context, _isEditing ? '保存成功' : '添加成功'); Navigator.pop(context); } diff --git a/lib/pages/profile_page.dart b/lib/pages/profile_page.dart index 8d645af..9a75033 100644 --- a/lib/pages/profile_page.dart +++ b/lib/pages/profile_page.dart @@ -6,6 +6,7 @@ import 'package:path/path.dart' as path; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../utils/user_prefs.dart'; +import '../utils/toast_util.dart'; import 'recycle_bin_page.dart'; import 'backup_page.dart'; import 'statistics_page.dart'; @@ -446,13 +447,7 @@ class _ProfilePageState extends State { /// 显示提示 void _showToast(String message) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(message), - behavior: SnackBarBehavior.floating, - duration: const Duration(seconds: 2), - ), - ); + ToastUtil.show(context, message); } /// 选择头像 diff --git a/lib/pages/recycle_bin_page.dart b/lib/pages/recycle_bin_page.dart index 7f540da..780d1de 100644 --- a/lib/pages/recycle_bin_page.dart +++ b/lib/pages/recycle_bin_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; +import '../utils/toast_util.dart'; /// 回收站页面 class RecycleBinPage extends StatefulWidget { @@ -246,9 +247,7 @@ class _RecycleBinPageState extends State with SingleTickerProvid await context.read().restoreMovie(movie.id); _loadDeletedItems(); if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('影视已恢复')), - ); + ToastUtil.show(context, '影视已恢复'); } } @@ -259,9 +258,7 @@ class _RecycleBinPageState extends State with SingleTickerProvid await context.read().permanentDeleteMovie(movie.id); _loadDeletedItems(); if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('已彻底删除')), - ); + ToastUtil.show(context, '已彻底删除'); } } } @@ -271,9 +268,7 @@ class _RecycleBinPageState extends State with SingleTickerProvid await context.read().restoreBook(book.id); _loadDeletedItems(); if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('书籍已恢复')), - ); + ToastUtil.show(context, '书籍已恢复'); } } @@ -284,9 +279,7 @@ class _RecycleBinPageState extends State with SingleTickerProvid await context.read().permanentDeleteBook(book.id); _loadDeletedItems(); if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('已彻底删除')), - ); + ToastUtil.show(context, '已彻底删除'); } } } @@ -296,9 +289,7 @@ class _RecycleBinPageState extends State with SingleTickerProvid await context.read().restoreNote(note.id); _loadDeletedItems(); if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('笔记已恢复')), - ); + ToastUtil.show(context, '笔记已恢复'); } } @@ -309,9 +300,7 @@ class _RecycleBinPageState extends State with SingleTickerProvid await context.read().permanentDeleteNote(note.id); _loadDeletedItems(); if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('已彻底删除')), - ); + ToastUtil.show(context, '已彻底删除'); } } } @@ -362,9 +351,7 @@ class _RecycleBinPageState extends State with SingleTickerProvid await context.read().clearRecycleBin(); _loadDeletedItems(); if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('回收站已清空')), - ); + ToastUtil.show(context, '回收站已清空'); } }, child: const Text('清空', style: TextStyle(color: Colors.red)), diff --git a/lib/pages/search_page.dart b/lib/pages/search_page.dart index 8de44ed..590d50a 100644 --- a/lib/pages/search_page.dart +++ b/lib/pages/search_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; +import '../utils/toast_util.dart'; import 'movie_detail_page.dart'; import 'book_detail_page.dart'; import 'note_detail_page.dart'; @@ -65,9 +66,7 @@ class _SearchPageState extends State { }); } catch (e) { setState(() => _isSearching = false); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('搜索失败: $e')), - ); + ToastUtil.show(context, '搜索失败: $e'); } } diff --git a/lib/widgets/custom_drawer.dart b/lib/widgets/custom_drawer.dart index 60c3be8..12b3294 100644 --- a/lib/widgets/custom_drawer.dart +++ b/lib/widgets/custom_drawer.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../utils/user_prefs.dart'; +import '../utils/toast_util.dart'; /// 自定义左侧弹出菜单 - 极简主义设计 class CustomDrawer extends StatelessWidget { @@ -188,12 +189,6 @@ class CustomDrawer extends StatelessWidget { /// 显示提示 void _showToast(BuildContext context, String message) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(message), - behavior: SnackBarBehavior.floating, - duration: const Duration(seconds: 2), - ), - ); + ToastUtil.show(context, message); } }