# 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 ```