Files
habo/docs/05-DEVELOPMENT.md
dazhuang aa69f2a91e feat: initial commit - Habo habit tracking app
- Complete MVP with Repository Pattern, SQLite storage
- Provider + ChangeNotifier state management
- Navigation 2.0 with deep link support
- Habit CRUD with twoDayRule, notifications, categories
- Backup/Restore via JSON
- Statistics with streak tracking
- Material You theme support
- Biometric lock support
- Desktop widget support
- 27 languages i18n structure
- Comprehensive test suite (87/89 passing)
2026-04-13 15:02:30 +00:00

25 KiB
Raw Blame History

Habo 开发文档

版本: 3.1.2+5115 | Flutter 3.41.1+ | Dart 3.11.0+

Habo 是一款极简风格的习惯追踪应用,支持 Android、iOS、Linux、macOS 多平台。所有数据存储在本地 SQLite 数据库中,无需服务端。


目录

  1. 项目概览
  2. 技术栈与依赖
  3. 目录结构
  4. 架构设计
  5. 数据模型
  6. 数据库 Schema
  7. 核心模块详解
  8. 导航系统
  9. 状态管理
  10. 国际化 (i18n)
  11. 主题系统
  12. 通知系统
  13. 备份与恢复
  14. 桌面端小组件
  15. 生物识别认证
  16. CI/CD 与构建
  17. 开发指南

1. 项目概览

Habo 是一个功能完整的习惯追踪应用,核心功能包括:

  • 习惯管理 — 创建、编辑、归档、删除习惯,支持拖拽排序
  • 两种习惯类型 — 布尔型(打卡/未打卡)和数值型(进度追踪,如跑步 5km
  • 日历视图 — 基于 table_calendar 的月度视图,标记每日状态
  • 连续天数 (Streak) — 支持普通模式和"两天法则"(允许间隔一天)
  • 分类系统 — 习惯可归属多个分类,支持按分类筛选
  • 统计分析 — 饼图总览、月度柱状图、个人习惯统计卡片
  • 通知提醒 — 每日提醒和成就/惩罚通知
  • 备份恢复 — JSON 文件导入/导出,支持跨设备迁移
  • 桌面小组件 — iOS/Android 主屏幕小组件显示今日进度
  • 生物识别锁 — 支持指纹/面容锁定应用
  • Material You — 支持动态取色主题

2. 技术栈与依赖

类别 技术 说明
框架 Flutter 3.41.1+ 跨平台 UI 框架
语言 Dart 3.11.0+ 支持 null safety
数据库 sqflite / sqflite_common_ffi SQLite移动端/桌面端)
状态管理 provider + ChangeNotifier 响应式状态管理
图表 fl_chart 统计图表渲染
日历 table_calendar 日历视图组件
通知 awesome_notifications 本地通知调度
国际化 flutter_localizations + intl ARB 文件管理多语言
字体 google_fonts + 动态取色 dynamic_color (Material You)
音效 flutter_soloud + audio_session 习惯完成音效反馈
认证 local_auth 指纹/面容生物识别
小组件 home_widget iOS/Android 桌面小组件
桌面窗口 window_manager Linux/macOS 窗口管理
测试 flutter_test + mocktail 单元测试与 mock
CI GitHub Actions 自动测试与 APK 构建
发布 fastlane 多平台商店发布自动化

3. 目录结构

Habo-master/
├── lib/                          # 应用主源码
│   ├── main.dart                 # 应用入口,初始化流程
│   ├── constants.dart            # 枚举类型和颜色常量
│   ├── themes.dart               # 主题定义(亮色/暗色/OLED
│   ├── helpers.dart              # 工具函数(日期解析等)
│   │
│   ├── model/                    # 数据模型层
│   │   ├── habit_data.dart       # HabitData 习惯数据模型
│   │   ├── habo_model.dart       # HaboModel 数据库操作层
│   │   ├── category.dart         # Category 分类模型
│   │   ├── settings_data.dart    # 设置数据模型
│   │   └── backup.dart           # 备份数据模型
│   │
│   ├── habits/                   # 习惯管理模块
│   │   ├── habit.dart            # Habit StatefulWidget日历卡片
│   │   ├── habits_manager.dart   # HabitsManager 业务逻辑中心
│   │   ├── habits_screen.dart    # 习惯列表主屏幕
│   │   ├── create_habit.dart     # 创建习惯页面
│   │   └── edit_habit.dart       # 编辑习惯页面
│   │
│   ├── statistics/               # 统计分析模块
│   │   ├── statistics.dart       # 统计数据计算逻辑
│   │   ├── statistics_screen.dart # 统计主屏幕
│   │   ├── statistics_card.dart  # 单个习惯统计卡片
│   │   ├── overall_statistics_card.dart # 总览饼图卡片
│   │   └── monthly_graph.dart    # 月度柱状图
│   │
│   ├── settings/                 # 设置模块
│   │   ├── settings_manager.dart # 设置管理器(持久化)
│   │   ├── settings_screen.dart  # 设置页面 UI
│   │   └── color_icon.dart       # 颜色选择器组件
│   │
│   ├── navigation/               # 导航系统
│   │   ├── routes.dart           # 路由常量
│   │   ├── app_router.dart       # RouterDelegate 实现
│   │   ├── app_state_manager.dart # 导航状态管理
│   │   ├── route_information_parser.dart # 深度链接解析
│   │   └── navigation.dart       # 导出文件
│   │
│   ├── repositories/             # 数据仓库层Repository Pattern
│   │   ├── habit_repository.dart      # 习惯仓库接口
│   │   ├── sqlite_habit_repository.dart # SQLite 实现
│   │   ├── event_repository.dart      # 事件仓库接口
│   │   ├── category_repository.dart   # 分类仓库接口
│   │   └── repository_factory.dart    # 仓库工厂DI
│   │
│   ├── services/                 # 服务层
│   │   ├── service_locator.dart  # 服务定位器DI 容器)
│   │   ├── notification_service.dart # 通知服务
│   │   ├── backup_service.dart   # 备份/恢复服务
│   │   ├── ui_feedback_service.dart  # UI 反馈服务Snackbar
│   │   ├── biometric_auth_service.dart # 生物识别服务
│   │   └── home_widget_service.dart   # 桌面小组件服务
│   │
│   ├── widgets/                  # 可复用 UI 组件
│   │   ├── habit_progress_indicator.dart # 进度指示器
│   │   ├── biometric_auth_wrapper.dart # 生物识别包裹组件
│   │   ├── category_filter_row.dart    # 分类筛选行
│   │   ├── progress_input_modal.dart   # 数值进度输入弹窗
│   │   ├── home_widget_data.dart       # 小组件数据模型
│   │   ├── habo_home_widget.dart       # 小组件渲染
│   │   └── text_container.dart         # 文本输入组件
│   │
│   ├── onboarding/               # 引导页
│   │   ├── onboarding_screen.dart
│   │   └── onboarding.dart
│   │
│   ├── l10n/                     # 国际化 ARB 文件27 种语言)
│   └── generated/                # 自动生成的代码intl 等)
│
├── test/                         # 测试目录
├── assets/                       # 静态资源
│   ├── images/                   # 图片(含 onboard/ 引导图)
│   ├── sounds/                   # 音效文件
│   └── google_fonts/             # 本地字体文件
│
├── android/                      # Android 平台代码
├── ios/                          # iOS 平台代码
├── linux/                        # Linux 平台代码
├── macos/                        # macOS 平台代码
├── fastlane/                     # 发布自动化配置
├── .github/workflows/ci.yml     # CI/CD 流水线
└── pubspec.yaml                  # 项目配置和依赖声明

4. 架构设计

4.1 整体架构

┌─────────────────────────────────────────────────────┐
│                   Presentation Layer                 │
│  (Screens, Widgets)                                  │
│  habits_screen  statistics_screen  settings_screen   │
├─────────────────────────────────────────────────────┤
│                  Business Logic Layer                │
│  HabitsManager (ChangeNotifier)                      │
│  SettingsManager                                     │
├─────────────────────────────────────────────────────┤
│                    Service Layer                     │
│  NotificationService  BackupService  UIFeedbackService│
│  BiometricAuthService  HomeWidgetService             │
├─────────────────────────────────────────────────────┤
│                  Repository Layer                    │
│  HabitRepository  EventRepository  CategoryRepository│
│  RepositoryFactory                                   │
├─────────────────────────────────────────────────────┤
│                    Data Layer                        │
│  HaboModel → SQLite (sqflite)                        │
└─────────────────────────────────────────────────────┘

4.2 设计模式

模式 应用场景
Repository Pattern HabitRepositoryEventRepositoryCategoryRepository 抽象数据访问
Service Locator ServiceLocator 单例管理全局服务实例
Factory Pattern RepositoryFactory 创建各仓库实例
Observer Pattern ChangeNotifier + Provider 实现响应式 UI 更新
Singleton Pattern HaboModelServiceLocator 确保单实例
Strategy Pattern HabitType 枚举区分布尔/数值习惯的不同处理逻辑

4.3 数据流

用户操作 → Widget
  → HabitsManager (ChangeNotifier)
    → Repository (数据访问抽象)
      → HaboModel (SQLite 操作)
        → Database

HabitsManager.notifyListeners()
  → Provider 更新
    → Widget 重建

4.4 初始化流程 (main.dart)

1. SettingsManager 初始化(读取持久化设置)
2. 创建 HaboModel 实例(共享数据库连接)
3. 调用 HaboModel.initDatabase() 初始化 SQLite
4. 初始化 ServiceLocator注册所有服务
5. 创建 HabitsManager注入仓库和服务依赖
6. 调用 HabitsManager.loadHabits() 加载数据
7. 初始化通知服务
8. 创建 AppRouter注入状态管理器
9. 启动日变化定时器(检测跨日自动刷新)
10. 渲染 MaterialApp.router

5. 数据模型

5.1 核心枚举 (constants.dart)

// 习惯类型
enum HabitType { boolean, numeric }

// 日状态类型
enum DayType { clear, check, fail, skip, progress }

// 主题模式
enum Themes { device, light, dark, oled, materialYou }

5.2 HabitData (model/habit_data.dart)

习惯的完整数据模型:

字段 类型 说明
id int? 数据库自增主键
position int 排序位置
title String 习惯标题
twoDayRule bool 是否启用两天法则
cue String 提示(触发器)
routine String 例行动作描述
reward String 奖励描述
showReward bool 是否显示奖励通知
sanction String 惩罚描述
showSanction bool 是否显示惩罚通知
accountant String 问责伙伴
advanced bool 是否显示高级选项cue/routine/reward
notification bool 是否启用通知提醒
notTime TimeOfDay 通知时间
events SplayTreeMap<DateTime, List> 事件记录(日期→事件列表)
habitType HabitType 布尔型或数值型
targetValue double 数值型目标值(默认 100
partialValue double 数值型部分进度增量(默认 10
unit String 数值型单位
categories List<Category> 所属分类列表
archived bool 是否已归档
streak int 当前连续天数(运行时计算)

事件列表结构 (events[date]):

布尔型:  [DayType, comment]
数值型:  [DayType, comment, progressValue, targetValue]

关键方法:

  • isCompletedForDate(date) — 判断某日是否完成
  • getProgressForDate(date) — 获取某日进度值
  • getProgressPercentage(date) — 获取进度百分比

5.3 Category (model/category.dart)

字段 类型 说明
id int? 自增主键
title String 分类名称
iconCodePoint int 图标 Unicode 码点
fontFamily String? 图标字体族(如 FontAwesome

6. 数据库 Schema

数据库版本: 9,文件: habo_db0.db

6.1 habits 表

CREATE TABLE habits (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    position INTEGER,            -- 排序位置
    title TEXT,                  -- 习惯标题
    twoDayRule INTEGER,          -- 两天法则开关 (0/1)
    cue TEXT DEFAULT '',         -- 提示触发器
    routine TEXT DEFAULT '',     -- 例行动作
    reward TEXT DEFAULT '',      -- 奖励
    showReward INTEGER,          -- 显示奖励 (0/1)
    advanced INTEGER,            -- 高级模式 (0/1)
    notification INTEGER,        -- 通知开关 (0/1)
    notTime TEXT,                -- 通知时间 (HH:MM)
    sanction TEXT DEFAULT '',    -- 惩罚
    showSanction INTEGER DEFAULT 0, -- 显示惩罚 (0/1)
    accountant TEXT DEFAULT '',  -- 问责伙伴
    habitType INTEGER DEFAULT 0, -- 习惯类型 (0=布尔, 1=数值)
    targetValue REAL DEFAULT 1.0, -- 目标值
    partialValue REAL DEFAULT 1.0, -- 部分增量
    unit TEXT DEFAULT '',        -- 单位
    archived INTEGER DEFAULT 0   -- 归档状态 (0/1)
);

6.2 events 表

CREATE TABLE events (
    id INTEGER,                  -- 外键 → habits.id
    dateTime TEXT,               -- 日期时间字符串
    dayType INTEGER,             -- DayType 枚举索引
    comment TEXT DEFAULT '',     -- 备注
    progressValue REAL DEFAULT 0.0, -- 进度值(数值习惯)
    targetValue REAL DEFAULT 0.0,   -- 目标值快照
    PRIMARY KEY(id, dateTime),
    FOREIGN KEY (id) REFERENCES habits(id) ON DELETE CASCADE
);

DayType 枚举值:

含义
0 clear — 清除
1 check — 完成
2 fail — 失败
3 skip — 跳过
4 progress — 进行中(数值型部分完成)

6.3 categories 表

CREATE TABLE categories (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title TEXT NOT NULL,         -- 分类名称
    iconCodePoint INTEGER NOT NULL, -- 图标码点
    fontFamily TEXT              -- 图标字体族
);

6.4 habit_categories 关联表

CREATE TABLE habit_categories (
    habit_id INTEGER NOT NULL,
    category_id INTEGER NOT NULL,
    PRIMARY KEY (habit_id, category_id),
    FOREIGN KEY (habit_id) REFERENCES habits(id) ON DELETE CASCADE,
    FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE CASCADE
);

6.5 数据库迁移历史

版本 变更
V1→V2 events 表增加 comment 字段
V2→V3 habits 表增加 sanctionshowSanctionaccountant 字段
V3→V4 habits 表增加 habitTypetargetValuepartialValueunitevents 增加 progressValue
V4→V5 events 表增加 targetValue;新建 categorieshabit_categories
V5→V6 habits 表增加 archived 字段
V6→V7 events 表确保有 targetValuecategories 增加 fontFamily
V7→V8 events 表确保有 targetValue
V8→V9 events 表确保有 targetValue

7. 核心模块详解

7.1 HabitsManager (habits/habits_manager.dart)

中心业务逻辑管理器,继承 ChangeNotifier,是整个应用的核心。

职责:

  • 管理 habits 和 categories 的内存状态
  • 协调 Repository 层的数据操作
  • 集成通知、备份、UI 反馈等服务
  • 处理拖拽排序、归档、undo 等交互逻辑

核心 API:

// 习惯 CRUD
Future<void> loadHabits()
Future<void> addHabit(Habit habit)
Future<void> editHabit(Habit habit)
Future<void> deleteHabit(int id)
Future<void> archiveHabit(int id)
void reorderList(int oldIndex, int newIndex)

// 事件操作
Future<void> addEvent(int id, DateTime date, List event)
Future<void> deleteEvent(int id, DateTime date)

// 分类操作
Future<void> loadCategories()
Future<void> addCategory(Category category)
Future<void> updateCategory(Category category)
Future<void> deleteCategory(int id)
Future<void> updateHabitCategories(int habitId, List<Category> categories)

// 服务调用
Future<void> createBackup()
Future<void> loadBackup(String path)
Future<void> resetNotifications()
void updateHomeWidget()

// 数据访问
List<Habit> get activeHabits    // 未归档习惯
List<Habit> get archivedHabits  // 已归档习惯
Habit? findHabitById(int id)

7.2 HaboModel (model/habo_model.dart)

直接操作 SQLite 数据库的底层类

  • 使用 sqflite(移动端)或 sqflite_common_ffiLinux/macOS
  • 管理数据库创建、迁移、CRUD
  • 处理 PRAGMA foreign_keys = ON 级联删除

7.3 Repository 层 (repositories/)

HaboModel 提供抽象接口,实现关注点分离:

  • HabitRepository — 习惯 CRUD、排序、批量操作
  • EventRepository — 事件增删查
  • CategoryRepository — 分类 CRUD 及关联管理
  • RepositoryFactory — 创建各 Repository 实例,注入 HaboModel

7.4 Service 层 (services/)

服务 职责
ServiceLocator 单例 DI 容器,初始化并持有所有服务实例
NotificationService 管理本地通知调度(每日提醒、奖励/惩罚)
BackupService 数据库备份为 JSON 文件、从 JSON 恢复
UIFeedbackService 统一的 Snackbar 消息展示(成功/失败/警告)
BiometricAuthService 封装 local_auth 生物识别认证
HomeWidgetService 更新 iOS/Android 主屏幕小组件数据

8. 导航系统

采用 Flutter Navigation 2.0,基于 RouterDelegate

路由定义

常量 路径 页面
splashPath / 启动页
habitsPath /habits 习惯列表主页
statisticsPath /statistics 统计页
settingsPath /settings 设置页
onboardingPath /onboarding 引导页
createHabitPath /create 创建习惯
editHabitPath /edit 编辑习惯
whatsNewPath /whatsnew 更新日志

深度链接

支持 habo:// scheme例如 habo://settings 直接跳转设置页。

关键类

  • AppRouterRouterDelegate 实现,管理页面栈
  • AppStateManager — 管理各页面的显示状态bool 标志位)
  • HaboRouteInformationParser — 解析 URL 到 HaboRouteConfiguration

9. 状态管理

使用 Provider + ChangeNotifier 模式:

MultiProvider(
  providers:
    - ChangeNotifierProvider<SettingsManager>
    - ChangeNotifierProvider<HabitsManager>
    - ChangeNotifierProvider<AppStateManager>
)
  • HabitsManager — 习惯数据变化时调用 notifyListeners(),驱动 UI 重建
  • SettingsManager — 设置变更时通知(主题、音效等)
  • AppStateManager — 导航状态变更通知
  • 注意: AppRouter 不监听 HabitsManager,避免数据变化导致非预期的导航跳转

10. 国际化 (i18n)

  • 使用 flutter_intl + ARB 文件管理
  • 文件位于 lib/l10n/intl_*.arb
  • 支持 27 种语言
    • 中文(简体/繁体)、英语、西班牙语、法语、德语、意大利语、葡萄牙语、俄语、日语(未列出但可能有)、阿拉伯语、希伯来语、波兰语、荷兰语、瑞典语、捷克语、越南语、印尼语、土耳其语、乌克兰语、加泰罗尼亚语、斯洛伐克语、巴斯克语、世界语、挪威语等
  • 生成代码在 lib/generated/ 目录

添加新语言:

  1. lib/l10n/ 下创建 intl_<locale>.arb
  2. 运行 flutter gen-l10n 生成代码

11. 主题系统

HaboTheme 类提供三种主题:

主题 说明
lightTheme 浅色主题,浅灰背景 (#FAFAFA)
darkTheme 深色主题,纯黑背景 (#000000)
oledTheme OLED 深色主题,纯黑背景

主题模式 (Themes 枚举):

  • device — 跟随系统
  • light — 强制浅色
  • dark — 强制深色
  • oled — OLED 黑色
  • materialYou — Material You 动态取色

特性:

  • 使用 Google Fonts 自定义字体
  • 主色调: #09BF30(绿色)
  • 支持平台差异iOS/Android 不同组件样式)

12. 通知系统

使用 awesome_notifications 实现本地通知:

  • 每日提醒 — 用户设定时间推送提醒
  • 奖励通知 — 完成习惯时触发(可配置音效)
  • 惩罚通知 — 习惯失败时触发

NotificationService 通过 HabitsManager 调用:

  • resetNotifications() — 重置所有习惯通知
  • removeNotifications(id) — 删除指定习惯的通知
  • handleHabitEventAdded() — 事件添加后触发通知

13. 备份与恢复

BackupService 提供完整的数据导入/导出:

  • 导出: 将所有 habits、events、categories 序列化为 JSON 文件
  • 导入: 从 JSON 文件解析并恢复到数据库
  • 兼容性: 支持旧版格式迁移
  • 文件选择: 使用 flutter_file_dialog(移动端)或 file_picker(桌面端)

14. 桌面端小组件

使用 home_widget 包实现 iOS/Android 主屏幕小组件:

  • 小组件类型: 170x170 圆形进度指示器
  • 数据传递: 通过 HomeWidgetService 更新数据
  • 显示内容: 今日习惯完成数量 / 总数量
  • 渲染: CircularProgressPainter 自定义绘制多段圆弧

15. 生物识别认证

  • BiometricAuthService 封装 local_auth
  • BiometricAuthWrapper Widget 包裹主内容
  • 支持指纹和面容识别
  • 应用从后台恢复时重新验证
  • 认证失败提供重试对话框

16. CI/CD 与构建

GitHub Actions (ci.yml)

触发条件: push/PR 到 maindevelop 分支

流水线:

  1. testflutter analyze + flutter test
  2. build-android(依赖 test 通过):
    • flutter build apk --release --split-per-abi --no-tree-shake-icons
    • 按 CPU 架构分拆 APKarm64-v8a, armeabi-v7a, x86_64
    • 上传构建产物

本地构建

# 安装依赖
flutter pub get

# 生成图标包
dart run flutter_iconpicker:generate_packs --packs fontAwesomeIcons

# 生成国际化代码
flutter gen-l10n

# 运行测试
flutter test

# 构建 APK
flutter build apk --release

# 构建 iOS
flutter build ios --release

# 桌面端
flutter build linux --release
flutter build macos --release

Fastlane

fastlane/ 目录包含多平台商店发布的自动化配置。


17. 开发指南

环境要求

  • Flutter SDK >= 3.41.1
  • Dart SDK >= 3.11.0
  • Android: Java 17, minSdk 21
  • iOS: Xcode (最新版)
  • Linux: 额外依赖 sqflite_common_ffi

项目约定

  1. 状态管理 — 使用 ChangeNotifier + Provider,新功能应创建 Manager 类
  2. 数据访问 — 通过 Repository 接口,不直接使用 HaboModel
  3. 服务依赖 — 通过 ServiceLocator 获取,不手动创建实例
  4. 国际化 — 所有用户可见文本必须使用 AppLocalizations,不硬编码字符串
  5. 主题 — 使用 HaboTheme 定义的颜色和样式,不直接写色值
  6. 数据库迁移 — 修改 Schema 必须新增迁移方法并更新 _dbVersion
  7. 测试 — 使用 mocktail mock Repository 层,测试业务逻辑而非 UI 渲染

添加新功能的典型流程

  1. model/ 中定义或修改数据模型
  2. repositories/ 中添加/更新 Repository 接口和实现
  3. services/ 中添加服务(如需要)
  4. HabitsManager 中添加业务逻辑方法
  5. 在对应的 screen/widget 中实现 UI
  6. lib/l10n/intl_en.arb 中添加国际化文本
  7. 编写单元测试

关键文件速查

需求 文件
添加新习惯字段 model/habit_data.dart + model/habo_model.dart + 数据库迁移
修改日历行为 habits/habit.dart
添加新统计图表 statistics/ 目录
修改通知逻辑 services/notification_service.dart
添加新设置项 settings/settings_manager.dart + settings_screen.dart
修改导航流程 navigation/app_router.dart + navigation/app_state_manager.dart
添加新语言 lib/l10n/intl_<locale>.arb
修改主题 themes.dart