# Habo 可复用素材清单

> 从原项目提取的静态资源、国际化文本、测试用例，作为 AI 复刻项目的起点素材

---

## 1. 静态资源清单

### 1.1 图片资源 (`assets/images/`)

| 文件 | 用途 | 格式 |
|------|------|------|
| `icon.png` | Android 应用图标 | PNG |
| `ios_icon.jpg` | iOS 应用图标 | JPG |
| `macos_icon.png` | macOS 应用图标 | PNG |
| `app_icon.png` | 通用应用图标 | PNG |
| `splash_icon.png` | 启动画面图标 | PNG |
| `splash_icon2.png` | 备用启动图标 | PNG |
| `android_foreground.png` | Android 自适应图标前景 | PNG |
| `android_background.png` | Android 自适应图标背景 | PNG |
| `android_monochrome.svg` | Android 单色图标 | SVG |
| `emptyList.svg` | 空列表占位图 | SVG |
| `noDataStatistics.svg` | 统计页空数据占位图 | SVG |

### 1.2 引导页图片 (`assets/images/onboard/`)

| 文件 | 用途 |
|------|------|
| `1.svg` | 第 1 步: 定义习惯 (空列表插图) |
| `2.svg` | 第 2 步: 记录天数 (习惯追踪插图) |
| `3.svg` | 第 3 步: 观察进步 (进度追踪插图) |

### 1.3 音效资源 (`assets/sounds/`)

| 文件 | 用途 | 说明 |
|------|------|------|
| `check.wav` | 打卡完成音效 | 成功完成的正向音效 |
| `click.wav` | 通用点击音效 | 失败/跳过等操作的反馈音效 |
| `sound_sources.txt` | 音效来源说明 | 开源协议信息 |

### 1.4 字体资源 (`assets/google_fonts/`)

**字体族**: Nunito（18 个字重/样式变体）

| 文件 | 字重 |
|------|------|
| Nunito-ExtraLight.ttf | 200 |
| Nunito-Light.ttf | 300 |
| Nunito-Regular.ttf | 400 |
| Nunito-Medium.ttf | 500 |
| Nunito-SemiBold.ttf | 600 |
| Nunito-Bold.ttf | 700 |
| Nunito-ExtraBold.ttf | 800 |
| Nunito-Black.ttf | 900 |
| 以及对应的 Italic 变体 | |

许可证: OFL (SIL Open Font License)

---

## 2. 国际化文本 (英文基准 ARB)

> 完整的 `intl_en.arb`，包含 **354 个键**，可直接复制为项目的国际化基准文件

```json
{
    "@@locale": "en",
    "habits": "Habits:",
    "statistics": "Statistics",
    "emptyList": "Empty list",
    "noDataAboutHabits": "There is no data about habits.",
    "topStreak": "Top streak",
    "currentStreak": "Current streak",
    "total": "Total",
    "unknown": "Unknown",
    "warning": "Warning",
    "allHabitsWillBeReplaced": "All habits will be replaced with habits from backup.",
    "restore": "Restore",
    "cancel": "Cancel",
    "settings": "Settings",
    "theme": "Theme",
    "firstDayOfWeek": "First day of the week",
    "notifications": "Notifications",
    "notificationTime": "Notification time",
    "soundEffects": "Sound effects",
    "showMonthName": "Show month name",
    "setColors": "Set colors",
    "backup": "Backup",
    "create": "Create",
    "onboarding": "Onboarding",
    "about": "About",
    "habo": "Habo",
    "copyright": "©2023 Habo",
    "termsAndConditions": "Terms and Conditions",
    "privacyPolicy": "Privacy Policy",
    "disclaimer": "Disclaimer",
    "sourceCode": "Source code (GitHub)",
    "ifYouWantToSupport": "If you want to support Habo you can:",
    "buyMeACoffee": "Buy me a coffee",
    "reset": "Reset",
    "done": "Done",
    "congratulationsReward": "Congratulations! Your reward:",
    "ohNoSanction": "Oh no! Your sanction:",
    "month": "Month",
    "week": "Week",
    "habitLoop": "Habit loop",
    "habitLoopDescription": "Habit Loop is a psychological model describing the process of habit formation. It consists of three components: Cue, Routine, and Reward. The Cue triggers the Routine (habitual action), which is then reinforced by the Reward, creating a loop that makes the habit more ingrained and likely to be repeated.",
    "cue": "Cue",
    "cueDescription": "is the trigger that initiates your habit. It could be a specific time, location, feeling, or an event.",
    "routine": "Routine",
    "routineDescription": "is the action you take in response to the cue. This is the habit itself.",
    "reward": "Reward",
    "rewardDescription": "is the benefit or positive feeling you experience after performing the routine. It reinforces the habit.",
    "editHabit": "Edit Habit",
    "createHabit": "Create Habit",
    "delete": "Delete",
    "habitTitleEmptyError": "The habit title can not be empty.",
    "save": "Save",
    "exercise": "Exercise",
    "habit": "Habit",
    "useTwoDayRule": "Use Two day rule",
    "twoDayRule": "Two day rule",
    "twoDayRuleDescription": "With two day rule, you can miss one day and do not lose a streak if the next day is successful.",
    "advancedHabitBuilding": "Advanced habit building",
    "advancedHabitBuildingDescription": "This section helps you better define your habits utilizing the Habit loop. You should define cues, routines, and rewards for every habit.",
    "at7AM": "At 7:00AM",
    "do50PushUps": "Do 50 push ups",
    "fifteenMinOfVideoGames": "15 min. of video games",
    "showReward": "Show reward",
    "remainderOfReward": "The reminder of the reward after a successful routine.",
    "habitContract": "Habit contract",
    "habitContractDescription": "While positive reinforcement is recommended, some people may opt for a habit contract. A habit contract allows you to specify a sanction that will be imposed if you miss your habit, and may involve an accountability partner who helps supervise your goals.",
    "donateToCharity": "Donate 10$ to charity",
    "sanction": "Sanction",
    "showSanction": "Show sanction",
    "remainderOfSanction": "The reminder of the sanction after a unsuccessful routine.",
    "dan": "Dan",
    "accountabilityPartner": "Accountability partner",
    "add": "Add",
    "haboNeedsPermission": "Habo needs permission to send notifications to work properly.",
    "allow": "Allow",
    "date": "Date",
    "check": "Check",
    "fail": "Fail",
    "skip": "Skip",
    "note": "Note",
    "yourCommentHere": "Your note here",
    "close": "Close",
    "createYourFirstHabit": "Create your first habit.",
    "modify": "Modify",
    "backupFailedError": "ERROR: Creating backup failed.",
    "restoreFailedError": "ERROR: Restoring backup failed.",
    "habitDeleted": "Habit deleted.",
    "undo": "Undo",
    "appNotifications": "App notifications",
    "appNotificationsChannel": "Notification channel for application notifications",
    "habitNotifications": "Habit notifications",
    "habitNotificationsChannel": "Notification channel for habit notifications",
    "doNotForgetToCheckYourHabits": "Do not forget to check your habits.",
    "themeSelect": "{theme, select, device {Device} light {Light} dark {Dark} oled {OLED black} materialYou {Material You} other{Device}}",
    "@themeSelect": {
      "placeholders": {
        "theme": {
          "type": "String"
        }
      }
    },
    "defineYourHabits": "Define your habits",
    "defineYourHabitsDescription": "To better stick to your habits, you can define:",
    "cueNumbered": "1. Cue",
    "routineNumbered": "2. Routine",
    "rewardNumbered": "3. Reward",
    "logYourDays": "Log your days",
    "successful": "Successful",
    "notSoSuccessful": "Not so successful",
    "skipDoesNotAffectStreaks": "Skip (does not affect streaks)",
    "observeYourProgress": "Observe your progress",
    "trackYourProgress": "You can track your progress through the calendar view in every habit or on the statistics page.",
    "backupCreatedSuccessfully": "Backup created successfully!",
    "backupFailed": "Backup failed!",
    "restoreCompletedSuccessfully": "Restore completed successfully!",
    "restoreFailed": "Restore failed!",
    "fileNotFound": "File not found",
    "fileTooLarge": "File too large (max 10MB)",
    "invalidBackupFile": "Invalid backup file",
    "progress": "Progress",
    "enterAmount": "Enter amount",
    "complete": "Complete",
    "saveProgress": "Save Progress",
    "currentProgress": "Current: {current} {unit}",
    "@currentProgress": {
      "placeholders": {
        "current": { "type": "String" },
        "unit": { "type": "String" }
      }
    },
    "targetProgress": "Target: {target} {unit}",
    "@targetProgress": {
      "placeholders": {
        "target": { "type": "String" },
        "unit": { "type": "String" }
      }
    },
    "progressOf": "{current} / {target} {unit}",
    "@progressOf": {
      "placeholders": {
        "current": { "type": "String" },
        "target": { "type": "String" },
        "unit": { "type": "String" }
      }
    },
    "numericHabit": "Progressive",
    "targetValue": "Target value",
    "partialValue": "Partial value",
    "unit": "Unit",
    "habitType": "Habit type",
    "booleanHabit": "Checkable (Yes/No)",
    "slider": "Slider",
    "input": "Input",
    "numericHabitDescription": "Numeric habits let you track progress in increments throughout the day.",
    "partialValueDescription": "To track progress in smaller increments",
    "categories": "Categories",
    "addCategory": "Add Category",
    "editCategory": "Edit Category",
    "category": "Category",
    "noCategoriesYet": "No categories yet",
    "createFirstCategory": "Create your first category to organize your habits",
    "pleaseEnterCategoryTitle": "Please enter a category title",
    "categoryAlreadyExists": "Category \"{title}\" already exists",
    "@categoryAlreadyExists": { "placeholders": { "title": { "type": "String" } } },
    "categoryCreatedSuccessfully": "Category \"{title}\" created successfully",
    "@categoryCreatedSuccessfully": { "placeholders": { "title": { "type": "String" } } },
    "categoryUpdatedSuccessfully": "Category \"{title}\" updated successfully",
    "@categoryUpdatedSuccessfully": { "placeholders": { "title": { "type": "String" } } },
    "categoryDeletedSuccessfully": "Category \"{title}\" deleted successfully",
    "@categoryDeletedSuccessfully": { "placeholders": { "title": { "type": "String" } } },
    "failedToSaveCategory": "Failed to save category: {error}",
    "@failedToSaveCategory": { "placeholders": { "error": { "type": "String" } } },
    "failedToDeleteCategory": "Failed to delete category: {error}",
    "@failedToDeleteCategory": { "placeholders": { "error": { "type": "String" } } },
    "selectCategories": "Select Categories",
    "selectedCategories": "Selected Categories ({count})",
    "@selectedCategories": { "placeholders": { "count": { "type": "int" } } },
    "allCategories": "All Categories",
    "deleteCategory": "Delete Category",
    "deleteCategoryConfirmation": "Are you sure you want to delete \"{title}\"?\n\nThis will remove the category from all habits that use it.",
    "@deleteCategoryConfirmation": { "placeholders": { "title": { "type": "String" } } },
    "noHabitsInCategory": "No habits in \"{title}\"",
    "@noHabitsInCategory": { "placeholders": { "title": { "type": "String" } } },
    "createHabitForCategory": "Create a habit and assign it to this category",
    "showCategories": "Show Categories",
    "archive": "Archive",
    "unarchive": "Unarchive",
    "archiveHabit": "Archive habit",
    "unarchiveHabit": "Unarchive habit",
    "archivedHabits": "Archived Habits",
    "noArchivedHabits": "No archived habits",
    "viewArchivedHabits": "View archived habits",
    "habitArchived": "Habit archived",
    "habitUnarchived": "Habit unarchived",
    "biometric": "Biometric",
    "biometricLockEnabled": "Biometric lock enabled",
    "biometricLockDisabled": "Biometric lock disabled",
    "authenticationError": "Authentication error",
    "biometricAuthenticationRequired": "Biometric authentication required",
    "setupFingerprintFaceUnlock": "Please set up your fingerprint or face unlock in device settings",
    "touchSensor": "Touch sensor",
    "biometricNotRecognized": "Biometric not recognized, try again",
    "biometricRequired": "Biometric required",
    "biometricAuthenticationSucceeded": "Biometric authentication succeeded",
    "deviceCredentialsRequired": "Device credentials required",
    "setupDeviceCredentials": "Please set up device credentials in settings",
    "setupTouchIdFaceId": "Please set up your Touch ID or Face ID in device settings",
    "reenableTouchIdFaceId": "Please reenable your Touch ID or Face ID",
    "biometricLock": "Biometric Lock",
    "biometricLockDescription": "Secure app with {authMethod}",
    "@biometricLockDescription": { "placeholders": { "authMethod": { "type": "String" } } },
    "authenticateToEnable": "Authenticate to enable biometric lock",
    "authenticateToAccess": "Please authenticate to access Habo",
    "authenticationRequired": "Authentication Required",
    "authenticationFailedMessage": "Please authenticate to access Habo using {authMethod}",
    "@authenticationFailedMessage": { "placeholders": { "authMethod": { "type": "String" } } },
    "tryAgain": "Try Again",
    "authenticating": "Authenticating…",
    "authenticate": "Authenticate",
    "buildingBetterHabits": "Building Better Habits",
    "authenticationPrompt": "Please authenticate using {authMethod} to access your habits",
    "@authenticationPrompt": { "placeholders": { "authMethod": { "type": "String" } } },
    "devicePinPatternPassword": "Device PIN, Pattern, or Password",
    "fingerprint": "Fingerprint",
    "iris": "Iris",
    "whatsNewTitle": "What's New",
    "whatsNewVersion": "Version {version}",
    "@whatsNewVersion": { "placeholders": { "version": { "type": "String" } } },
    "featureNumericTitle": "Numeric values in habits",
    "featureNumericDesc": "Track counts like glasses of water or pages read",
    "featureDeepLinksTitle": "URL scheme (deep links)",
    "featureDeepLinksDesc": "Open Habo directly to screens like settings or create",
    "featureCategoriesTitle": "Categories",
    "featureCategoriesDesc": "Organize habits with category filters",
    "featureArchiveTitle": "Archive",
    "featureArchiveDesc": "Hide habits you no longer track without deleting",
    "featureMaterialYouTitle": "Material You theme (Android)",
    "featureMaterialYouDesc": "Dynamic colors that match your wallpaper",
    "featureSoundTitle": "New sound engine",
    "featureSoundDesc": "Adjustable volume",
    "featureLockTitle": "Lock feature",
    "featureLockDesc": "Secure the app with Face ID / Touch ID / biometrics",
    "featureIosSoundMixingTitle": "Fixed sound mixing",
    "featureIosSoundMixingDesc": "Habo sounds no longer interrupt your music or podcasts",
    "featureHomescreenWidgetTitle": "Homescreen widget",
    "featureHomescreenWidgetDesc": "View your habit progress at a glance from your home screen (experimental)",
    "featureLongpressCheckTitle": "Longpress check",
    "featureLongpressCheckDesc": "Longpress on habit buttons to quickly change status",
    "haboSyncComingSoon": "Coming Soon",
    "haboSyncDescription": "Sync your habits across all your devices with Habo's end-to-end encrypted cloud service.",
    "haboSyncLearnMore": "Learn more at habo.space/sync",
    "habitsToday": "Habits today",
    "or": "or",
    "oneTapCheck": "Single tap to check",
    "tapCheckLongPressMenu": "Tap to check, long press for menu",
    "categoryName": "Category name",
    "createCategory": "Create category",
    "all": "All",
    "selectIcon": "Pick an icon",
    "searchIcons": "Search"
}
```

---

## 3. 支持的语言 (27 种)

| 代码 | 语言 |
|------|------|
| `en` | English (基准) |
| `zh_Hans` | 中文简体 |
| `zh_Hant` | 中文繁體 |
| `es` | Español |
| `fr` | Français |
| `de` | Deutsch |
| `it` | Italiano |
| `pt` | Português |
| `pt_BR` | Português (Brasil) |
| `ru` | Русский |
| `ja` | (可能缺失, 需确认) |
| `ar` | العربية |
| `he` | עברית |
| `pl` | Polski |
| `nl` | Nederlands |
| `sv` | Svenska |
| `cs` | Čeština |
| `sk` | Slovenčina |
| `uk` | Українська |
| `vi` | Tiếng Việt |
| `id` | Bahasa Indonesia |
| `tr` | Türkçe |
| `ca` | Català |
| `ta` | தமிழ் |
| `nb_NO` | Norsk bokmål |
| `eo` | Esperanto |
| `ia` | Interlingua |
| `ckb` | کوردی |

---

## 4. 测试用例清单

> 13 个测试文件，覆盖核心业务逻辑

### 4.1 单元测试

| 文件 | 测试目标 | 测试用例数 |
|------|----------|-----------|
| `test/habits/habits_manager_test.dart` | HabitsManager CRUD | 13 |
| `test/habits/habits_manager_updated_test.dart` | Repository 模式集成 | 8 |
| `test/habits/habits_manager_fixed_test.dart` | 归档功能 | 8 |
| `test/habits/habits_manager_notifications_test.dart` | 通知调度 | 3 |
| `test/habits/backup_enhancement_test.dart` | 备份格式 | 4 |
| `test/services/backup_service_test.dart` | 备份服务 | 7 |
| `test/services/backup_feature_comprehensive_test.dart` | 备份完整性 | 18 |
| `test/services/notification_service_test.dart` | 通知服务 | 11 |
| `test/app_test.dart` | 应用初始化 | 4 |
| `test/repositories/repository_test.dart` | Repository 模式 | 6 |

### 4.2 Widget 测试

| 文件 | 测试目标 | 测试用例数 |
|------|----------|-----------|
| `test/widgets/habit_details_widget_test.dart` | 习惯详情组件 | 3 |
| `test/widgets/habit_list_widget_test.dart` | 习惯列表组件 | 2 |

### 4.3 集成测试

| 文件 | 测试目标 | 测试用例数 |
|------|----------|-----------|
| `test/integration/habit_crud_integration_test.dart` | 完整 CRUD 流程 | 2 |

### 4.4 测试 Mock 基础设施

| 文件 | 内容 |
|------|------|
| `test/mocks/mock_repositories.dart` | MockHabitRepository, MockEventRepository, MockCategoryRepository, MockBackupRepository + InMemory 实现用于集成测试 |

### 4.5 关键测试场景摘要

**HabitsManager 测试**:
- 初始化时从 Repository 加载习惯
- 空列表正确处理
- 创建习惯并分配正确位置
- 编辑更新已有习惯
- 删除习惯并支持 Undo
- 归档/取消归档切换
- 活跃/归档习惯正确过滤
- 位置排序更新
- 通知调度触发

**备份测试**:
- 正确的 JSON 结构验证
- 时间戳格式验证
- 空数据备份处理
- 事件类型保留
- 分类关联保留
- 大数据集处理
- 损坏数据检测
- 10MB 文件大小限制
- 并发操作处理

**通知测试**:
- 空习惯列表不崩溃
- 习惯通知调度
- 事件添加/删除触发通知
- 多习惯批量通知
- 当日/非当日事件区分

---

## 5. 备份文件格式规格

### 5.1 当前格式 (Version 3)

```json
{
  "version": 3,
  "habits": [
    {
      "id": 1,
      "position": 0,
      "title": "Exercise",
      "twoDayRule": false,
      "cue": "At 7:00AM",
      "routine": "Do 50 push ups",
      "reward": "15 min. of video games",
      "showReward": true,
      "advanced": true,
      "notification": true,
      "notTime": {"hour": 7, "minute": 0},
      "events": {
        "2024-01-01 00:00:00.000": [1, ""],
        "2024-01-02 00:00:00.000": [2, "Tired"]
      },
      "sanction": "Donate 10$ to charity",
      "showSanction": true,
      "accountant": "Dan",
      "habitType": 0,
      "targetValue": 1.0,
      "partialValue": 1.0,
      "unit": ""
    }
  ],
  "categories": [
    { "id": 1, "title": "Health", "iconCodePoint": 58718, "fontFamily": "fontAwesomeFlutter" }
  ],
  "habit_categories": [
    { "habit_id": 1, "category_id": 1 }
  ],
  "metadata": {
    "import_timestamp": "2024-01-15T10:30:00.000Z"
  }
}
```

### 5.2 旧版兼容格式 (数组)

```json
[
  {
    "id": 1,
    "title": "Exercise",
    "position": 0,
    "events": {},
    ...
  }
]
```

### 5.3 事件类型编码

| 值 | DayType | 含义 |
|----|---------|------|
| 0 | clear | 清除/无事件 |
| 1 | check | 完成 |
| 2 | fail | 失败 |
| 3 | skip | 跳过 |
| 4 | progress | 进度（部分完成） |

---

## 6. pubspec.yaml 关键配置

```yaml
name: habo
version: 3.1.2+5115

environment:
  sdk: ">=3.11.0 <4.0.0"
  flutter: ">=3.41.1"

flutter:
  uses-material-design: true
  generate: true
  assets:
    - assets/
    - assets/images/
    - assets/images/onboard/
    - assets/sounds/
    - assets/google_fonts/

flutter_intl:
  enabled: true

flutter_native_splash:
  color: "#FAFAFA"
  color_dark: "#000000"
  image: assets/images/splash_icon.png
  image_dark: assets/images/splash_icon.png
  ios_content_mode: center
  android_gravity: center
  fullscreen: false
  android_12:
    color: "#FAFAFA"
    color_dark: "#000000"
    image: assets/images/splash_icon.png
  android: true
  ios: true
  web: false
```
