# focus_flutter **Repository Path**: wsgalaxy/focus_flutter ## Basic Information - **Project Name**: focus_flutter - **Description**: 多任务专注管理程序。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-23 - **Last Updated**: 2026-06-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Focus(Flutter 版) 一个**始终置顶**的多任务跟踪小窗口:在多个任务之间切换"当前活跃任务",记录每个任务的累计工作时长,并为每个任务维护独立的 Todo 列表。 > 形态定位:360 × 520 的紧凑桌面窗口,悬浮在工作区一角,随时切换 / 记录。 本项目是 [`focus-qt`](../focus-qt/) 的 **Flutter 重写版本**,复用相同的领域模型与 SQLite 表结构(便于跨实现互通),但全面使用 Dart / Flutter / Riverpod 生态重新实现,并为后续"任务↔系统窗口绑定"等差异化能力打下基础。 ## 功能特性(MVP) - **多任务管理**:任意创建、编辑、删除任务。 - **单一活跃任务**:同一时刻只有一个任务在计时;切换 / 暂停时自动结算并持久化。 - **每任务独立 Todo**:每个任务维护自己的 Todo 列表,活跃任务切换时 Todo 列表同步切换。 - **精确计时**:基于系统时间差(`now - startedAt`),不受 `Timer` 休眠 / 漂移影响;UI 每秒刷新一次显示。 - **始终置顶**:默认开启,可一键切换并持久化偏好。 - **暗色 / 亮色主题**:跟随系统配色,亦可手动切换。 - **数据持久化**:本地 SQLite(`focus.db`,位于 `getApplicationSupportDirectory()`),无需配置。 - **关闭即结算**:关闭窗口前自动结算正在进行的计时段。 ## 技术栈 - **UI**:Flutter(Material 3,`useMaterial3: true`) - **业务逻辑 / 状态管理**:Dart 3,`flutter_riverpod` - **持久化**:SQLite(`sqflite_common_ffi`,桌面通过 FFI 直链 SQLite,无需 platform channel) - **窗口控制**:`window_manager`(始终置顶、最小尺寸、关闭事件) - **偏好持久化**:`shared_preferences` - **测试**:`flutter_test` ## 架构原则 - **分层**:`Widget (UI) → Riverpod Notifier (ViewModel) → Repository (抽象) → SQLite` - **依赖注入**:所有服务通过构造函数注入;`main.dart` 作为唯一组合根,通过 `ProviderScope(overrides: [...])` 装配生产实现;测试通过 `ProviderContainer(overrides: [...])` 注入假实现 - **接口隔离**:业务层只依赖抽象(`TaskRepository` / `TodoRepository` / `TimeSegmentRepository` / `TimeSource` / `WindowService`),具体实现可在测试中替换 - **纯函数优先**:领域逻辑(`canTransition`、`formatDuration`、`formatAccumulated`)写为无副作用纯函数 - **禁止 `DateTime.now()`**:所有业务代码使用 `TimeSource.nowMs()`,测试中注入 `FakeTimeSource` - **禁止单例 / 全局可变状态**:所有状态通过 Riverpod 容器管理 ## 目录结构 ``` lib/ ├── main.dart # 组合根 ├── domain/ # Task / Todo / TimeSegment / TaskStatus ├── persistence/ # Schema / Bootstrap / Repository 抽象 + SQLite 实现 ├── timer/ # TimeSource / SystemTimeSource / ActiveTaskTimer ├── viewmodels/ # Riverpod Provider + AppController + Notifier ├── ui/ # 主题 / 入口 Widget / 主界面 / 对话框 / 字符串 └── platform/ # WindowService 抽象 + WindowManagerService test/ ├── support/ # FakeTimeSource / TempDatabase ├── domain/ # 状态转换测试 ├── persistence/ # SQLite Repository 测试(临时文件数据库) ├── timer/ # ActiveTaskTimer 测试(假时钟) ├── ui/ # 纯函数 UI 工具测试(如 formatDuration) └── viewmodels/ # AppController 集成测试 openspec/ └── changes/ # 需求规格与变更(spec-driven 流程) ``` ## 构建与运行 ### 前置 - Flutter SDK ≥ 3(含 Dart 3.12+)。 - Windows 桌面:需要启用 **开发者模式**(`start ms-settings:developers`)以允许插件链接所需的 symlink;或使用管理员权限编译。 ### 网络代理 若 `flutter pub get` / hook 下载(如 `package:sqlite3` 从 GitHub 下载预编译 `sqlite3.dll`)遇到网络问题,可启用代理: ```bash source ~/.setup_proxy # 该文件已预置 http_proxy / https_proxy flutter pub get ``` 或者将本地 `sqlite3.dll` 放入项目根目录(已在 `.gitignore` 中),并在 `pubspec.yaml` 中保留: ```yaml hooks: user_defines: sqlite3: source: system ``` ### 命令 ```bash # 安装依赖 flutter pub get # 调试运行(Windows 桌面) flutter run -d windows # 构建发布版(Windows) flutter build windows # 运行所有单元测试 flutter test # 静态检查 flutter analyze ``` ## 测试 当前测试套件(68 cases,全部通过): | 文件 | 关注点 | 用例数 | |------|--------|--------| | `test/domain/task_status_transitions_test.dart` | 状态机合法 / 非法转换、字符串互转 | 8 | | `test/persistence/sqlite_task_repository_test.dart` | 任务 CRUD、单一活跃约束、级联删除 | 16 | | `test/persistence/sqlite_todo_repository_test.dart` | Todo CRUD、勾选 completedAt 翻转、任务删除级联 | 11 | | `test/persistence/sqlite_time_segment_repository_test.dart` | 计时段 durationMs 由实现计算、级联 | 5 | | `test/timer/active_task_timer_test.dart` | 启停 / 切换计时、`FakeTimeSource` 假时钟、不依赖墙钟 | 12 | | `test/ui/duration_format_test.dart` | 时间格式化纯函数 | 10 | | `test/viewmodels/app_controller_test.dart` | AppController 完整编排流程 | 10 | 测试可测性原则: - 所有依赖"现在时间"的逻辑通过 `TimeSource` 抽象访问,测试注入 `FakeTimeSource` - SQLite Repository 测试使用 `Directory.systemTemp.createTempSync` 创建临时数据库文件 - Riverpod Provider 通过 `ProviderContainer(overrides: [...])` 在测试中替换实现 ## 已知限制(MVP 阶段) - **无系统托盘**:关闭窗口即退出应用(关闭前自动结算计时)。 - **无报表 / 统计图表**:仅展示每个任务的累计耗时数值;`time_segments` 表已记录分段历史,供未来扩展。 - **无任务排序 / 拖拽**:任务列表按"活跃优先 + 更新时间倒序"自动排列。 - **无子 Todo 嵌套**:Todo 是扁平的单层列表。 - **无 Todo 优先级 / 截止时间**:Todo 仅有内容 + 是否完成。 - **无数据导出 / 导入**。 - **无国际化**:界面文案目前仅有中文,但集中在 `lib/ui/strings.dart`。 - **无任务↔窗口绑定**:是相对 Qt 版本的差异化目标,留作下一个独立 openspec change(`add-window-binding`)。 ## 数据位置 - 数据库:`%APPDATA%//focus.db`(Windows,由 `getApplicationSupportDirectory()` 决定) - 用户偏好(置顶 / 主题):`shared_preferences` 默认位置 重置全部数据时手动删除 `focus.db` 即可。 ## 复杂需求管理 本项目使用 [openspec](https://github.com/wesleyfox/openspec) 流程管理需求与变更。当前变更: - `openspec/changes/implement-core-mvp/`:核心 MVP(任务管理 / Todo / 计时 / 持久化 / 窗口行为) 未来计划: - `add-window-binding`:任务↔系统窗口绑定与前台化(Flutter 版本核心差异化能力) ## 开发约定 - **源代码编码**:UTF-8(无 BOM),换行 LF - **注释 / 文档 / 提交信息**:使用中文 - **命名**:变量 / 函数 / 类 / 文件名使用英文,遵循 Dart 官方约定 - **提交规范**:[Conventional Commits](https://www.conventionalcommits.org/);`git commit -s` 添加 `Signed-off-by` - **代码风格**:`flutter_lints`(`analysis_options.yaml`),新增告警必须修复或显式抑制并注释原因 ## 许可 (待定)