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)
This commit is contained in:
2026-04-13 15:02:30 +00:00
commit aa69f2a91e
212 changed files with 16694 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

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

282
lib/generated/l10n.dart Normal file
View File

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