From 448028478070dd2ed8d6b5b21aa52ab187a376ae Mon Sep 17 00:00:00 2001 From: whitlocktech Date: Fri, 22 May 2026 17:21:30 -0500 Subject: [PATCH] Initial commit: Implement base health and cycle tracking application. - Set up Android project structure with Gradle 8.7, Kotlin 2.0, and Hilt. - Implement Room database with entities for Profiles, Day Logs, Conditions, Cycle Records, and Intimacy Logs. - Integrate Jetpack Compose for the UI layer including Navigation and Material3. - Develop a cycle prediction engine to calculate menstruation, fertile windows, and ovulation based on user history. - Implement core screens: - **Onboarding:** Initial profile setup for female/male users. - **Calendar:** Monthly view showing cycle phases, logged symptoms, and intimacy records. - **Day Detail:** Detailed logging for symptoms (with ratings), period status, notes, and intimacy encounters. - **Cycle Insights:** Visualization of cycle phases and historical cycle length trends. - **Health Trends:** Frequency and recurrence analysis of logged health conditions over various time ranges. - **Settings:** Profile management, data clearing, and app theme configuration. - Add DataStore for managing user preferences such as active profile and onboarding status. Signed-off-by: whitlocktech --- .gradle/8.7/checksums/checksums.lock | Bin 0 -> 17 bytes .gradle/8.7/checksums/md5-checksums.bin | Bin 0 -> 32897 bytes .gradle/8.7/checksums/sha1-checksums.bin | Bin 0 -> 83723 bytes ...rariesForLibs$AndroidPluginAccessors.class | Bin 0 -> 920 bytes ...ibs$AndroidxActivityLibraryAccessors.class | Bin 0 -> 938 bytes ...ForLibs$AndroidxCoreLibraryAccessors.class | Bin 0 -> 918 bytes ...riesForLibs$AndroidxLibraryAccessors.class | Bin 0 -> 1509 bytes .../dm/LibrariesForLibs$BundleAccessors.class | Bin 0 -> 765 bytes ...ariesForLibs$ComposeLibraryAccessors.class | Bin 0 -> 1881 bytes ...ComposeMaterialIconsLibraryAccessors.class | Bin 0 -> 953 bytes ...Libs$ComposeMaterialLibraryAccessors.class | Bin 0 -> 1143 bytes ...iesForLibs$ComposeUiLibraryAccessors.class | Bin 0 -> 1717 bytes ...ibs$ComposeUiToolingLibraryAccessors.class | Bin 0 -> 1233 bytes ...iesForLibs$DatastoreLibraryAccessors.class | Bin 0 -> 924 bytes ...ibrariesForLibs$HiltLibraryAccessors.class | Bin 0 -> 1492 bytes ...rLibs$HiltNavigationLibraryAccessors.class | Bin 0 -> 932 bytes ...brariesForLibs$KotlinPluginAccessors.class | Bin 0 -> 1093 bytes ...bs$KotlinxCoroutinesLibraryAccessors.class | Bin 0 -> 941 bytes ...ariesForLibs$KotlinxLibraryAccessors.class | Bin 0 -> 1563 bytes ...KotlinxSerializationLibraryAccessors.class | Bin 0 -> 944 bytes ...iesForLibs$LifecycleLibraryAccessors.class | Bin 0 -> 1545 bytes ...ibs$LifecycleRuntimeLibraryAccessors.class | Bin 0 -> 1027 bytes ...s$LifecycleViewmodelLibraryAccessors.class | Bin 0 -> 944 bytes ...esForLibs$NavigationLibraryAccessors.class | Bin 0 -> 919 bytes .../dm/LibrariesForLibs$PluginAccessors.class | Bin 0 -> 1844 bytes ...ibrariesForLibs$RoomLibraryAccessors.class | Bin 0 -> 1063 bytes .../LibrariesForLibs$VersionAccessors.class | Bin 0 -> 1963 bytes .../accessors/dm/LibrariesForLibs.class | Bin 0 -> 7225 bytes ...nPluginsBlock$AndroidPluginAccessors.class | Bin 0 -> 962 bytes ...ock$AndroidxActivityLibraryAccessors.class | Bin 0 -> 2238 bytes ...nsBlock$AndroidxCoreLibraryAccessors.class | Bin 0 -> 2218 bytes ...luginsBlock$AndroidxLibraryAccessors.class | Bin 0 -> 2944 bytes ...orLibsInPluginsBlock$BundleAccessors.class | Bin 0 -> 891 bytes ...PluginsBlock$ComposeLibraryAccessors.class | Bin 0 -> 3418 bytes ...ComposeMaterialIconsLibraryAccessors.class | Bin 0 -> 2253 bytes ...lock$ComposeMaterialLibraryAccessors.class | Bin 0 -> 2485 bytes ...uginsBlock$ComposeUiLibraryAccessors.class | Bin 0 -> 3161 bytes ...ock$ComposeUiToolingLibraryAccessors.class | Bin 0 -> 2584 bytes ...uginsBlock$DatastoreLibraryAccessors.class | Bin 0 -> 2224 bytes ...sInPluginsBlock$HiltLibraryAccessors.class | Bin 0 -> 2936 bytes ...Block$HiltNavigationLibraryAccessors.class | Bin 0 -> 2232 bytes ...InPluginsBlock$KotlinPluginAccessors.class | Bin 0 -> 1135 bytes ...ck$KotlinxCoroutinesLibraryAccessors.class | Bin 0 -> 2241 bytes ...PluginsBlock$KotlinxLibraryAccessors.class | Bin 0 -> 2998 bytes ...KotlinxSerializationLibraryAccessors.class | Bin 0 -> 2244 bytes ...uginsBlock$LifecycleLibraryAccessors.class | Bin 0 -> 2980 bytes ...ock$LifecycleRuntimeLibraryAccessors.class | Bin 0 -> 2378 bytes ...k$LifecycleViewmodelLibraryAccessors.class | Bin 0 -> 2244 bytes ...ginsBlock$NavigationLibraryAccessors.class | Bin 0 -> 2219 bytes ...orLibsInPluginsBlock$PluginAccessors.class | Bin 0 -> 1970 bytes ...sInPluginsBlock$RoomLibraryAccessors.class | Bin 0 -> 2465 bytes ...rLibsInPluginsBlock$VersionAccessors.class | Bin 0 -> 2005 bytes .../dm/LibrariesForLibsInPluginsBlock.class | Bin 0 -> 9517 bytes .../metadata.bin | 1 + .../gradle/accessors/dm/LibrariesForLibs.java | 775 +++++++++++++ .../dm/LibrariesForLibsInPluginsBlock.java | 1023 +++++++++++++++++ .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .gradle/8.7/fileHashes/fileHashes.bin | Bin 0 -> 147033 bytes .gradle/8.7/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes .../8.7/fileHashes/resourceHashesCache.bin | Bin 0 -> 63311 bytes .../buildOutputCleanup.lock | Bin 0 -> 17 bytes .gradle/buildOutputCleanup/cache.properties | 2 + .gradle/config.properties | 2 + .gradle/file-system.probe | Bin 0 -> 8 bytes .idea/.gitignore | 3 + .idea/AndroidProjectSystem.xml | 6 + .idea/gradle.xml | 18 + .idea/migrations.xml | 10 + .idea/misc.xml | 10 + .idea/runConfigurations.xml | 17 + .idea/vcs.xml | 6 + app/build.gradle.kts | 76 ++ app/proguard-rules.pro | 2 + app/src/main/AndroidManifest.xml | 23 + .../java/com/hsdiary/HSDiaryApplication.kt | 7 + app/src/main/java/com/hsdiary/MainActivity.kt | 22 + .../java/com/hsdiary/data/db/AppDatabase.kt | 133 +++ .../com/hsdiary/data/db/dao/ConditionDao.kt | 33 + .../data/db/dao/ConditionDefinitionDao.kt | 23 + .../com/hsdiary/data/db/dao/CycleRecordDao.kt | 32 + .../java/com/hsdiary/data/db/dao/DayLogDao.kt | 32 + .../com/hsdiary/data/db/dao/IntimacyLogDao.kt | 32 + .../com/hsdiary/data/db/dao/ProfileDao.kt | 29 + .../db/entity/ConditionDefinitionEntity.kt | 15 + .../data/db/entity/ConditionEntryEntity.kt | 24 + .../data/db/entity/CycleRecordEntity.kt | 27 + .../hsdiary/data/db/entity/DayLogEntity.kt | 25 + .../data/db/entity/IntimacyLogEntity.kt | 28 + .../hsdiary/data/db/entity/ProfileEntity.kt | 17 + .../hsdiary/data/model/ConditionCategory.kt | 14 + .../java/com/hsdiary/data/model/CyclePhase.kt | 13 + .../com/hsdiary/data/model/ProfileType.kt | 3 + .../hsdiary/data/model/ReproductiveStatus.kt | 30 + .../data/preferences/UserPreferences.kt | 57 + .../data/repository/CycleRepository.kt | 62 + .../data/repository/DayLogRepository.kt | 67 ++ .../data/repository/IntimacyRepository.kt | 28 + .../data/repository/ProfileRepository.kt | 25 + app/src/main/java/com/hsdiary/di/AppModule.kt | 24 + .../java/com/hsdiary/di/DatabaseModule.kt | 32 + .../hsdiary/domain/CyclePredictionEngine.kt | 159 +++ .../hsdiary/domain/model/CyclePrediction.kt | 24 + .../com/hsdiary/ui/calendar/CalendarScreen.kt | 330 ++++++ .../hsdiary/ui/calendar/CalendarViewModel.kt | 207 ++++ .../com/hsdiary/ui/components/ProfileChip.kt | 77 ++ .../ui/components/ProfileSwitchSheet.kt | 78 ++ .../hsdiary/ui/daydetail/DayDetailScreen.kt | 475 ++++++++ .../ui/daydetail/DayDetailViewModel.kt | 206 ++++ .../ui/insights/CycleInsightsScreen.kt | 207 ++++ .../ui/insights/CycleInsightsViewModel.kt | 65 ++ .../hsdiary/ui/navigation/AppNavigation.kt | 60 + .../java/com/hsdiary/ui/navigation/Screen.kt | 12 + .../hsdiary/ui/onboarding/OnboardingScreen.kt | 165 +++ .../ui/onboarding/OnboardingViewModel.kt | 77 ++ .../com/hsdiary/ui/settings/SettingsScreen.kt | 242 ++++ .../hsdiary/ui/settings/SettingsViewModel.kt | 95 ++ .../main/java/com/hsdiary/ui/theme/Color.kt | 31 + .../main/java/com/hsdiary/ui/theme/Theme.kt | 56 + .../main/java/com/hsdiary/ui/theme/Type.kt | 15 + .../hsdiary/ui/trends/HealthTrendsScreen.kt | 176 +++ .../ui/trends/HealthTrendsViewModel.kt | 130 +++ .../res/drawable/ic_launcher_background.xml | 8 + .../res/drawable/ic_launcher_foreground.xml | 10 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/values/strings.xml | 4 + app/src/main/res/values/themes.xml | 4 + build.gradle.kts | 8 + gradle/libs.versions.toml | 47 + gradle/wrapper/gradle-wrapper.properties | 7 + local.properties | 8 + settings.gradle.kts | 23 + 132 files changed, 5824 insertions(+) create mode 100644 .gradle/8.7/checksums/checksums.lock create mode 100644 .gradle/8.7/checksums/md5-checksums.bin create mode 100644 .gradle/8.7/checksums/sha1-checksums.bin create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidPluginAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxActivityLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxCoreLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$BundleAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$ComposeLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$ComposeMaterialIconsLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$ComposeMaterialLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$ComposeUiLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$ComposeUiToolingLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$DatastoreLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$HiltLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$HiltNavigationLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$KotlinPluginAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$KotlinxCoroutinesLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$KotlinxLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$KotlinxSerializationLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$LifecycleLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$LifecycleRuntimeLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$LifecycleViewmodelLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$NavigationLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$PluginAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$RoomLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$VersionAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidPluginAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxActivityLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxCoreLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$BundleAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$ComposeLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$ComposeMaterialIconsLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$ComposeMaterialLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$ComposeUiLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$ComposeUiToolingLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$DatastoreLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$HiltLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$HiltNavigationLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$KotlinPluginAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$KotlinxCoroutinesLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$KotlinxLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$KotlinxSerializationLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$LifecycleLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$LifecycleRuntimeLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$LifecycleViewmodelLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$NavigationLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$PluginAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$RoomLibraryAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$VersionAccessors.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock.class create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/metadata.bin create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/sources/org/gradle/accessors/dm/LibrariesForLibs.java create mode 100644 .gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/sources/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock.java create mode 100644 .gradle/8.7/executionHistory/executionHistory.lock create mode 100644 .gradle/8.7/fileHashes/fileHashes.bin create mode 100644 .gradle/8.7/fileHashes/fileHashes.lock create mode 100644 .gradle/8.7/fileHashes/resourceHashesCache.bin create mode 100644 .gradle/buildOutputCleanup/buildOutputCleanup.lock create mode 100644 .gradle/buildOutputCleanup/cache.properties create mode 100644 .gradle/config.properties create mode 100644 .gradle/file-system.probe create mode 100644 .idea/.gitignore create mode 100644 .idea/AndroidProjectSystem.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/migrations.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 .idea/vcs.xml create mode 100644 app/build.gradle.kts create mode 100644 app/proguard-rules.pro create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/com/hsdiary/HSDiaryApplication.kt create mode 100644 app/src/main/java/com/hsdiary/MainActivity.kt create mode 100644 app/src/main/java/com/hsdiary/data/db/AppDatabase.kt create mode 100644 app/src/main/java/com/hsdiary/data/db/dao/ConditionDao.kt create mode 100644 app/src/main/java/com/hsdiary/data/db/dao/ConditionDefinitionDao.kt create mode 100644 app/src/main/java/com/hsdiary/data/db/dao/CycleRecordDao.kt create mode 100644 app/src/main/java/com/hsdiary/data/db/dao/DayLogDao.kt create mode 100644 app/src/main/java/com/hsdiary/data/db/dao/IntimacyLogDao.kt create mode 100644 app/src/main/java/com/hsdiary/data/db/dao/ProfileDao.kt create mode 100644 app/src/main/java/com/hsdiary/data/db/entity/ConditionDefinitionEntity.kt create mode 100644 app/src/main/java/com/hsdiary/data/db/entity/ConditionEntryEntity.kt create mode 100644 app/src/main/java/com/hsdiary/data/db/entity/CycleRecordEntity.kt create mode 100644 app/src/main/java/com/hsdiary/data/db/entity/DayLogEntity.kt create mode 100644 app/src/main/java/com/hsdiary/data/db/entity/IntimacyLogEntity.kt create mode 100644 app/src/main/java/com/hsdiary/data/db/entity/ProfileEntity.kt create mode 100644 app/src/main/java/com/hsdiary/data/model/ConditionCategory.kt create mode 100644 app/src/main/java/com/hsdiary/data/model/CyclePhase.kt create mode 100644 app/src/main/java/com/hsdiary/data/model/ProfileType.kt create mode 100644 app/src/main/java/com/hsdiary/data/model/ReproductiveStatus.kt create mode 100644 app/src/main/java/com/hsdiary/data/preferences/UserPreferences.kt create mode 100644 app/src/main/java/com/hsdiary/data/repository/CycleRepository.kt create mode 100644 app/src/main/java/com/hsdiary/data/repository/DayLogRepository.kt create mode 100644 app/src/main/java/com/hsdiary/data/repository/IntimacyRepository.kt create mode 100644 app/src/main/java/com/hsdiary/data/repository/ProfileRepository.kt create mode 100644 app/src/main/java/com/hsdiary/di/AppModule.kt create mode 100644 app/src/main/java/com/hsdiary/di/DatabaseModule.kt create mode 100644 app/src/main/java/com/hsdiary/domain/CyclePredictionEngine.kt create mode 100644 app/src/main/java/com/hsdiary/domain/model/CyclePrediction.kt create mode 100644 app/src/main/java/com/hsdiary/ui/calendar/CalendarScreen.kt create mode 100644 app/src/main/java/com/hsdiary/ui/calendar/CalendarViewModel.kt create mode 100644 app/src/main/java/com/hsdiary/ui/components/ProfileChip.kt create mode 100644 app/src/main/java/com/hsdiary/ui/components/ProfileSwitchSheet.kt create mode 100644 app/src/main/java/com/hsdiary/ui/daydetail/DayDetailScreen.kt create mode 100644 app/src/main/java/com/hsdiary/ui/daydetail/DayDetailViewModel.kt create mode 100644 app/src/main/java/com/hsdiary/ui/insights/CycleInsightsScreen.kt create mode 100644 app/src/main/java/com/hsdiary/ui/insights/CycleInsightsViewModel.kt create mode 100644 app/src/main/java/com/hsdiary/ui/navigation/AppNavigation.kt create mode 100644 app/src/main/java/com/hsdiary/ui/navigation/Screen.kt create mode 100644 app/src/main/java/com/hsdiary/ui/onboarding/OnboardingScreen.kt create mode 100644 app/src/main/java/com/hsdiary/ui/onboarding/OnboardingViewModel.kt create mode 100644 app/src/main/java/com/hsdiary/ui/settings/SettingsScreen.kt create mode 100644 app/src/main/java/com/hsdiary/ui/settings/SettingsViewModel.kt create mode 100644 app/src/main/java/com/hsdiary/ui/theme/Color.kt create mode 100644 app/src/main/java/com/hsdiary/ui/theme/Theme.kt create mode 100644 app/src/main/java/com/hsdiary/ui/theme/Type.kt create mode 100644 app/src/main/java/com/hsdiary/ui/trends/HealthTrendsScreen.kt create mode 100644 app/src/main/java/com/hsdiary/ui/trends/HealthTrendsViewModel.kt create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/drawable/ic_launcher_foreground.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/themes.xml create mode 100644 build.gradle.kts create mode 100644 gradle/libs.versions.toml create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 local.properties create mode 100644 settings.gradle.kts diff --git a/.gradle/8.7/checksums/checksums.lock b/.gradle/8.7/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..85fd1615b2908860971fadf43544cf43d72d276d GIT binary patch literal 17 UcmZSX;QGy9Qu->30Ss8A0547h`v3p{ literal 0 HcmV?d00001 diff --git a/.gradle/8.7/checksums/md5-checksums.bin b/.gradle/8.7/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..2f7f21df1bde2235f7b127b0feb5918a5040907b GIT binary patch literal 32897 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 MPQl8WX;7{FAA@oVaR2}S literal 0 HcmV?d00001 diff --git a/.gradle/8.7/checksums/sha1-checksums.bin b/.gradle/8.7/checksums/sha1-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..f797fbf38e3897e4b61554e9f81171ce3c018952 GIT binary patch literal 83723 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 Yt>R9h%zr}-4J6+~4NdkH_M0ew2f`=Hb^rhX literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$BundleAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$BundleAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..b8e1f351f9b59cc4f8c7f489305cd538555fba07 GIT binary patch literal 765 zcmbVKO-~y!5FLk*g%G~d_Q0_c2U7fz`DI|@A6ai8Z_u1VcGV2;r!x$$*( rZ-1-0wfF$){uin);|K+ndtt6fR)Ger%G{Kw0&B1#3JGk&2Uvau&QtI< literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$ComposeLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$ComposeLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..866c9827fcde03785d31e811446318927de971ee GIT binary patch literal 1881 zcmb_cSx-|z6#k~Py|h$WEFvnhSg{o4svv4gh)`_M6k}2$@y+S&*o?VLGxrwdPpKp# z2_`=Iq;LKpUNnWy z%TkxNCzQ=i-QXTKoszy%a6QEh@7c%N#hNG!yC`g9CrhV}+DYUqg^ojp@RGEpx6F`D z=FaUSJ+q~umtnmb$uNZLI?C0HmY$OZ#g!Cp)={)~6B)-UJFeK^6t(1L?S5yaVG}_V zeHvmhT);(!r>Dhj$72XNA8er*GXEjlC^Yo=Ar8hcgi8$5CN~U9?U<|>UbJ{`WP6qh zr8NvQte&T!~>6R~aT+lj*czSUYtZoha#ETxaMrYK<^gaI7d*^hONh zn4tDFl%U>VSWM>L^KGu1+%D;PPf5F!o@sGUtSBpITNZ`VU)47RKE*KD0JrLGHqQ{u zI7Nc(&q-UntXKu1Uh{%UC*hLtRvn8WkvsuDLnJRtHuoxuY~P;1WT`!9t~~jUIO^&f zL`9364GM2K#fm8oIh$TiGsGyo23shNz9y9+*XI9RjYV7`@J;EDhSo})1h&gZGeq-F zMHwP1{X!4dI`D89%=sTo89uj(p&66Au5dLxU|4DH?lTQPhIqH}r{N((vKjrT)ELH( zCH6@DMLW9~M(a17g~22>e1OJ&fTjq|5!wy;6eJk}{Q|OUpSEzuP^66Udf3xsWi!SKwj&nt#KLuE4N0lV>xNvk`|b7+USMs@2CTGomOR6?nf!%JC{h z;RIZy%c?&=IXVImC8Q)8s-YvH~05gsx0 zmRb0x6=T@BZpk7%WoR!~Ur==&$28S-SjKbOp$fefkYwSJklZ3`kL=*D9UgrF`$QVU zonX@m{2+N3+Y}LE_h-34bhsUTM*ZVT@K4+$PX#;l?as9OctB@JuizmbSL+1g37(<; E8zNC2P5=M^ literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$ComposeMaterialLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$ComposeMaterialLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..3418aec1bf6d1d8c77375e34d518873fccdc9820 GIT binary patch literal 1143 zcmb_bU279T6g_v7bep*L%cg3ztx6x#6uK|^R4IgLu#hTJDfl=$8N$eBCd_QK`Bw@` z!9st4zo7J~zeK!At;8r&VqfmuoxA7UuQT7ie?0;47>`N_kPDHIP{0)7z`AzacA}N4 zSafx)O{Sa?X)Hx1QrnJeiO-yn+4IATz%$iVrlpMRH~7}N{`!6|`Qwr>^;8?3?GPH3 z=6~nd-Z%&`P1qY{l2UnZosV0cxTzB-oL0VJ9s7R0ZaZD;)t=z0wMciRHU8qKe(e%i zL$yyrq5Hb5b?*AXj;O<6G~&CoKL=;~~}vl~MM8O_y*bO%m3|_ByUEJY+2d{FsU5z=B{e zV4q(z+eQ9*g8VREu5KQIs>cZ5RzIV7gxN2c`!ocW+0G!x_Kbn23_D}+5^n#bSmBd6 qT43PZ$6t^^2H>38@9-JmE|&RRW}*Q1u#zvbR9Eo;1GTPloy8wddtbEx literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$ComposeUiLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$ComposeUiLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..bdbc84794f6f4c7ec6563ef34e3b2ecccf43854a GIT binary patch literal 1717 zcmb_c-A)rh6#k|ZmX-=wKm|b*tCS*Lf6$u}3|4E1g_smc^vdaWT*qv8HnY1ZZ>5P! zqKOaS0~xQ3XA6Z=idFDp=gc`f=R5!B`>!wG04!oLi5Pke#8c=+AH$~7wrOi#bA-t~ zX-YQ`+U1UE@qjzZHdm^Cpt%)1dbj)Iq40!T6Rx#gBB|2bnMznaB4p@WlCBJv8A{pm zscjVIHVyPMthORqmhgS0eX~|K%d)DumclP7O?N+2RCQ1J;+fn~%8{-JrmKHn^4EM6-H++km4tH&{5@6>*cTZ_4zTmohTdyw`39yKUbI%EQ)4z8a!u7jM;z(E%zn=K(1i>W$M+$w z&@{!sFiBrJ8gp9Fak|rHrt=bUcZrV?9m~z{faSizc%J)+#14i&VfX|6V3?+J5IuDM zB*h;XB}$Yx15PjZ;Y!U*6K!FD67XhUOWiNbs?D&{NxO4FhU~6X((N&{s_p+i zqrQEbLyn;o>VBfFsHL*zw2q~U3Mk;Jk75zmaGha)`m8V%)@oyeUO#BduHi-s+tP;i zw$dDzI+4fYLgR#CV*;WULL;~n3@@tf_k6&En5!u0I77$Qw`aRbj2_6IFu~F9O+AMj z4CQ&swZw>l6d!z)7~V`1UUUJI!5`>e8jHC}SN=v0wc}1|)k%{imclS(nz~2)m)lZ_ z!?fQO=9qV5iWIn=&}67oFVPG`z9S>WU1|vb_7afY*$Hvu2^nZ3)}=yn*2`$`GZjJdVK`dDLVTr}JZ)y;5wk-mLwGE}Fl zPh_)5YYZC~sm(`);pKF}f6xM{?R+(0lU|AkhMV*wSRzaBpVnLCtx?<~o85W(73?$Z zsO^zY7HpN)72KhWQSSO#4Zz=5dJpCToYrfwNdMjijar2Lia)OC7}>o141f=NT1!@O^=n!UYOl0=D*Sx z1t0ta{G-IV*3b|u6n(hanc4aA-F&k@et!E7;03lCsNhNsaCT?O?;niZhSnhq!UMCYhv|~1G$q#ZC-M0_s z)y{8b{du&&kC{v$g_oV-2Xkt4W?ZUAfvros+sl76<^0qp#QNyB(p9ML=ZWO64XvZM z#biwU&Wtnhtfmx>F3>BqJ69@LAKBEIP_Wc^e}$CZGD^e2o(O4P9||`Ulg&9j%#$Lc z3lh6~g1<4!3yx`EOU$k1+3l7?QE0w#j(9&a-jk28snB1X{y#00!p3DQ72%OWXR-R6 zt;@Jo*!(NIcq$81k>>!Bs(c3`*TmWqyY$y~o_&S-ESkct(v}nIxyajCmxwa<$yqKC o?W{*%Q2(?P+`}F5RInjm>rA_gdvccP72L;zYF$7)#ADQd0S=%MqW}N^ literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$HiltLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$HiltLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..ca41dc8268603b75f15040d15d2fac6f68a00131 GIT binary patch literal 1492 zcmb_cYflqF6g{`JEG^|B79S`+i5O8{wU*J5Ga)(f?xK|W6!zg&YU|xet!K9;11jzQW$WM&Le|C!kV#x8(86o(iI)$ zDjiF!Md*4W7NH5;YAcGZ@ZyK>w>Oq#M`~YcZ==qu#%>gw-PRwAguw-+RlG>3ml`L| zQJGzHFhqFN%j9`7ij0k1zwI_u%L=PxR5zB#QSq?~<5jV)0ud{tx3@Q{JCH1L7Ez%aGEd^3eV%R4zGx?yf67qrN=m&$`B?A z`8Rxm^FsU9C_l$~&gO9r=lNniD@7~`_ezboVqLhQ(1F{Gt+GnB_@=7j{adle+p;$TsKOx&xffjMs zGXB*OAPfDXg^kr~c6a2iu!-9u+%f-(@w=hib9-g6LKtR=wcScac(!Le!jnD$C%G6t zj;85aPuBU=2$TJ;pHJ?CuWnhh9c!V8A{jZDB~*J2eylDh6b|Zh2e$~NUiQQ4BV78M ziwnsQ{T+s@?7tMhU&JlJO~IoykNE-P??s;7<$1C{S)SVjmA}DxQT~MNCdNKv{NomI zn!lqMV2&kZ=m82GSr0BVFri2yadgTPg)cbsVHcF-0IlE(ucTNB;o3oYx15Pc3I+bn@XX(^vUNI9fMiZ6&us!CBHfRt89K|SN_4vW#oj%;s4{uNw6 z;=m8!MI@;38@QC)Q;$b1KbAs;QRR z1ad~@GEqV0Hj}-v4^AcF>HEdO6Pl7q$t3dud##(dM#cCKr$FsM8yyY>2JPX0-_hMW z*}#Ut?pvLQj!`q6si3XtBz7{jo?^tf6rs_;Wn2+>wt8WbkoVSknNH+TkDYRw{J=Wa zed{^rJN}h!aXjxWA^eKOkqRX6xIKKQW=iJDWO5XoHd%LX{b5sQXF4S(U;b3O0@c1v z8NWHyhK`HLnA|Hh&e;=Z6#9$u1zPQMC998gW>hE~<6oZxaZazVdg-n=|wdL}Ag z(t2dmBB$Rxb`QDscw`Hg&_I{I|Q-3hAoaL tWAC40foOj#`h@z2wP1tm?5SXz*UqVS1G~JJ@Ct6?cD2q$+`&E6e*kNt6%zme literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$KotlinPluginAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$KotlinPluginAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..d1b21e6ead5c57b5e609a0815ae264a287a689bd GIT binary patch literal 1093 zcmbVL%We}f6g{4VP7=}wf%1m7kVOip-XJ!qB1I{Y5K*ZV)V(ufMuv$U*`A8>Rj>hx z1s}k#uw;pZxXGk6Bw18wB#(W4j(yI(*WZ7C{RZGE>JV2`db*j7@lAMVv}5 zMv5!#rPU(kk?pi9AVKy8{ z`&tZAic}Km+qqMQdgB6DGnD%((ZXkz_=gvu?9cicP3p@tCwZQO^A>2fnz^7(Zir!n z)b;;$Qt6w_MzX8M>Nn@JzBf)LCHaNc(sokeoOB_!7}~RS`>)PqSj`1b+bqNbhQ{o% zXGLDt4y1KyLtuycE1<^&6v4)?h{mh5+CqUoAbj-r$rrFsG^Og&I0hj2LE|Q_6Ez11 z<0ye^;b)XT&Vhg821NqgB+#v8r1d4FUo)iJ%ScxiNrl2+Qh+;?JMZEi{cCi4fcw}+ Lnf&hHATQc%x0yJltB*wNTqHP676 z2Z0Mn9C!d83NhOdh(aYQICwlWo^L$kZ~X21m#+XGU@Jxi7a~*}xQLp-k)upzq|#hV zH8IlIpvkISCMu}hWwJZ+fm9M6pUe&(>4~`6OuNus@X|MNxt~0 zbOfqBmok2Jz$HH~#v@HH)hK6AoaxY=bs*4eohw;=XfmrpL5zQO4#@s;g^GfC&Fp!3 z$Rv$bJ}39krA4lPv)MV|+T)=sDA9dW*1NI%e(mx>1R77Q)zr(C_u5CeEzn(L;GZT- zVEwGwif~t;wU~X*)LHxr?EIBs?C|hZ_DdAQiZJ@az{K8uhA__!YLMs$hiN}qziWa$cwRUKO#2X(3 z5>+LT_y9f%G0uftr~(PR?Ch@3o|!YAneRWod;@R~cT$KTY9MAJjs#)P(;cg$Mca{< zI8c^y1F2o%Shfg+<8`cR%MY}$gU3gM50B)5blcLkdv(6`bT8lRwtl-LB4VWfYaE|bBQRZ1bLfkuar6$z=gWePjM8gozn^?mILctNX&Eo#3i_nO)9`2jqn5T%5VmAAdayor2!;dIL9k4Fi~j nW@n)vIJO*vBG|+h+s%HodEAaAd7^Bih;XQEqr^7Dwv6OYUx(ui literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$KotlinxSerializationLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$KotlinxSerializationLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..50bcb450cbe4fa3015dc434671bc6e34b8e7bcd1 GIT binary patch literal 944 zcmbtT&2AGh5dIuOwh4hkY56HoR4IqFNbv>rlB!Zvhy)}EX;II3cg@PJV@I~PYIqf{ zeE_(C#DNFkp%AkT5mD$Ng2RqyX6GBv%s2k=^V@d-PqEcN1y>?eo4AS^!;y74&z;D$ zo9XM=Mxi*gUa8D|6QI(kY?U2N9GtonvoJ0}Wh@&}`y5ZZHhz?@Uway>*^vBR)`x z6HZCrw~ln*dNoZM&u5$lO?opRwUat2f@Iih501sD;98iR$H6I+cXt*$96NieGU@o6 z-%6LEdT2AkuMU)vuZvM4-CL1p@OHaN z`H)B&2|XisXtP4gKWugnsPIN?3zy2iDvRA%oL{G$21E0OG147s;l1<`?lbh}8ThBo zVpzXyw<0`bXwPS#(R3NVG}UDo#y0Iwg`NmVvhr<^TqSFZ?9yM`eexCTGieMrOPfxx zk0ftljUvj}#}`;2+Fgsjp#Etg_#C&%Q^7iY8yDIg+@-UGS8xxT)jAdN0FO}r1vVuc A1poj5 literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$LifecycleLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$LifecycleLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..000a76cdef5a73e84fa12ab49584633ba453b4f5 GIT binary patch literal 1545 zcmb_c+iuf95IvKdi7~X4lv1G3rh#0F@C$E2NFfkW5kR6S5|0~ai559_wRR}^B@hw_ zs!B!T1NbP!I7ve=q^NGjql>^X>cLR{*zh(?kME11Sq>WC$%^ckQkg9aq|7 zSJ}!7rS^ntJ0cXW-?eM)Ak@MMAG{fTxG#65*O8txXz;DC2Zfz}`?pI%=8p1Ic$d&9 zHUHU1wcIjrim*M+z=Gp50V!EwqwB!`HkI3QhG=Is?a*&-z}ddU6C9)Q%oy zVdAs_%fcC)CEPnXah#Em_V+xg3HARV*o1*(6y!MzOE^y`y25dW>W&vic=U_=Bf)cJ zscK-E2~VD!mXdotza!mvmQ3VEx-ME+#U(;Hu50E~!s9uV&7`XmQgsfIu+UVVeA4f= zrG75jF5j448IB8wy_U*z_?=OA?A2oONmPWVbJ0%-;t6I4=8oUjj%=t%%JK;Cvo&tL z60ZeEvF&lO)?E<TKq717C8ld;`JKVd5r>?hOWe+ khaB4mgA&MNlWl$&Z2>n@Ssounlo3skA}VZiY`2j80lur+JOBUy literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$LifecycleRuntimeLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$LifecycleRuntimeLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..c997146bd94b32f6b4bbe45c9bcb3814a23ac77a GIT binary patch literal 1027 zcmbtT%We}f6g^HuCJBK;+5qLzhm=LyO7RAz)FB(4cAa&I59Tii4}1wxfm<1 zw3k+klt;pg)FiwcI&VefpPf%1p31S*vDDF|PpGkz<}eE{fefVsrIkNq=(h&{9iy{* zQbw6!BUPs|nnbB=+e~{klI_Th#>UAis<KY4WH_1+8AZ}LV;zr2e4s)rtdg#8 zEa|Q}n0b6PbvQMcbY~>0B(hR?$?&8#cq`5XPlZnS&|9UG&hBDyV{6V-EG>WeOX-wx zi=lBj^LPH7q1ZDqxn3P8Enj4#P}nIB0_9*a zd11XerLj7GOw${QbT;*46KARXGv>}=hZ;jEKF^D&4ozkw*;jeujl~wX^QJM>jK4{~S7R(`}Q` z953zde**hJ8bdw5lLY%p=Ni_@BDdWlNhpH7dhijI_Y1}sXb@7s9WuJRjI_Fh^zApP afO|jb8@NxhPL2wAfJem&Wxk1RRDJ+d8z#yC literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$LifecycleViewmodelLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$LifecycleViewmodelLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..8bd91b1c6666d9fa82b9fa2608bf7cbfe6b66af1 GIT binary patch literal 944 zcmbtT&2AGh5dIuOwh4jK((+em11dYI-|%37J;x#uFE)h8nI!sMm27*94v~UmC|0g7ZNpW7*du zue_$vbDs6k=r3{(7b)j1v(6%nyNNxij07Gx`)|}#Nuz8k2btG4ZSSu(IPq?(6Y}!q zFQqL|?sBmL>wRtMMLr&pf2Br-ky=Vwciw_Pqj{lZ)qzf}%5u-~uP+dCv|6F^nLcIy zf;?fG#>y<{J#k5H=r^D3W3Ih6aJi4Er;B>GS0AudJcvO3nYHA*Muk8j!X1ImG6nxM zTLN3>O;?0_0?p;@3#QH^Sm5E`DaHdHpAvr&uoT7LV7boLF53lOIXL_T@qsmg>xIob z#5a~3*kq5wcke6~hz>TRkEp(1asG}QjFhm&Yx_*QiCerE;U(P0-Ex(S*ui~Ne*!E~ B8r%Q? literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$NavigationLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$NavigationLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..b418a9148bac5605e76407ecff699e5f9dc5c37d GIT binary patch literal 919 zcmbtTO>Yx15Pc3I+bn_7(DG5B2q}lOmFf%PlB!Y^h=i0@NI^a0?7AzXjUA1>5&2he z0f_@YfWN|(Gh((O5QQRDaPW9$JTrctH~#Yd(`NuruoI(#D-o&4~I0zdiWx zJ370kYgiL#S~WG93dY%k#EmD;>liVvMQAi|9XAAe%XcM-_TG_~=~xcTh!h#^`;J)m zt&?A+=0~&cBAme|q*c%YPuqhxYN}+eY$k_+jLkZ`tM8eRo0?RUeEC!92vmD6<^1)5 zvHGMKk2Jkfqntf)rbBNIU7*#zRI&QdWLAZOIREt}QVv%UDhlR|>GJZJSsAN*!RE0` zi(LPvuXDuM+2#tUmT^>XFC_7Uz0beCKIPopHTdC@RMcp%VT zuD)REB4P!$|4uC)^SD&_CxE3WzW~d1wszPq{k6UQj}Y%!6S!I0yhD6txq&7}l(CP_ qbAf2D8GS(g-AeE`++t4!o4mHpwcEJEdzoIrU2IqD4B|c>qW%MdkP#68 literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$PluginAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$PluginAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..782e7b284095cf136d32d8972d389a575516c71f GIT binary patch literal 1844 zcmbVNTT|0e5dKaIgw`Nh0YN|ntCn(!S3rYk1sNSWh=aq7k7;^{M?=y%Ng4T9IwLUZ zj59v!i*NoM#|>$*hNzW?X7^lnzi;>KZomHc@Cm?8+|58iN=2K7c62a2@uaQW(yTaK zH>*MyZos8$I=W>BrsLUqvFr!Zw1S7Pqk|=0jN2^THLu z0)v$=#hh2Aw=F7M>T7kSZe+wS9$~S>H_e(8Y;frd&s~hT8RHu&IvMUY!&nygeNXy& zWlJxKvNWaO{<0@Y_j5(JB0W)w7#AB?)5ze23Qa>7PBP53>@MbqA>D}3XBdwM)i^s6 zeTaWb!)atGdzR;J3Y%dzZr)-}GEk8UJ@#to!&!#ms%cr2faKU2ioXFha`GSPGgJ&P zEVP`p6)$jv8_Qh={SoaU4Z}FkFjS|Vc$?vV>#P$!7@fGl(Dp(&L57kwrr{!T44Ngm z8Ssc4!%V*P(%d$6$8>FdJ&?k+jeox@`M%7MdgWIMVbQB_hVGJZ`D$&e%;ht)?9h&C z^WYJoGvx9uxTM-z7q)8#HA%*+Ett$VXQ+D6qk7HfdKBBQHZ~RvDm!Ac67tQEQm+(- z#Td+Sii3!Uz7O7<;lclSOnx}xxbD@Y#g|2x$KH68Plqo?FZtMYxm z*~5Uck4e&LqM<;*q5Bb%jHFt~j_hId&7on459Ko^Xh*>$t)`NUE+rU!X)>CIPNpH! zFv$?9otXE;alX;fRa{HBIvBtDo#fgc5PfS*oTOPYHv+9%Z5X=|8|{sI{)`${W!z|e0G{<}tJ z=eUY0!>TnV-3v`RR*AHA)Ugtv(ZDL!7@jPa2}7A>#%4T9`9O`Vuu5iqW6952N0j9h zoOb7dbmP!U;UvT3_TZg35j+t(=0j(djypTcO^mHMQIWL#)tS?&;u1r3cEk5>Qbm)Y zF+15@JC#ymzh@#c>jS0b%RC)P`&x_=LRMnwdS_iRwA$yW#!wroSPPe1O7P|!l>Oxv zgmvmIiJ0+2(kd0nT;oF%<%#?)YUiLsO+&;Q1(d=hK=P(?-g^T zF+A5=+Fl~EOlASL7`lsE{nOepTrFF?0QVW%i`nM_mu&(iDcc2X(`I?}UH~7gcqsI} zLZ`cg7I-iLTteFXMe=ZKR`WLQkZn?Rk6OCt*QniXJV5OyKPVn9 literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$VersionAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs$VersionAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..2136c9c8a8059cfa436f10c90041abfa471bf25b GIT binary patch literal 1963 zcmbW1O-~a+7{~upkS?{n3W~3YqPBpn3L;oQO93@B1g+uXY1j_y$g=vuDqq zz34>~4}JhYl<`^Gnx&lsF-^A5%sjv6<-han?>|3(0hq@|3JG*2(VfN_^f2rw?b@#9 zWlz|=B5mo1Li^ma9UgK|xpsap2sL-YjibiFx~K@hEPSWFNxMqdCwGMor1G0fhMr~V z%W##!$rRh7SG20hve5QU(`Z7ucE^q~*2O-rdSNqHp;25eyKBK>7@$gIO@{S?I;^Nb zq>#edB+_a0p`T$XUWMa`AW%B6%ZGMR?rE;22sV`_J7~3%Z#glfT+vF(u#hRf<27!3 z+;{C#sHN}bvhAgJ^q8|S$k4^ziiKf{=roF4Q->Bt7?O_CVkw z=q*#H0m&>ZTw>^cE4|Rd6^7Bs+U7Os@{q)DHg4e>>3^U?Px=fxTyulb%wJHsSU{-pd2 zlbKV+`UxDbC_4kmXMKS98>GRDxTfqRD6~LFzVMUZJ6G>#(IRLz6PWayct)i}E72PCJaXMTWvBa>l@o{<9*x26EtLiR$|b76Lii1J&QpPOwgzSdKrV}Owa`b^d<()o1lvZ zNW`FrCg`#OQZZ=31YI>i^%(TX1dSV@4>4%b1Wg#Ak1=S;1l=@1pJLEs6LiY}eU3pn i6LiM_efb9^uzY-VSFlR|!*q!gc!E57X>8W8j^4j{2c!M~ literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibs.class new file mode 100644 index 0000000000000000000000000000000000000000..2defd49c05e4c51211e7e043e8e901779349b2f3 GIT binary patch literal 7225 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 CvB25@ literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..0f388d52b0286a7f404cf044b188a3fc2bc6130a GIT binary patch literal 2944 zcmb_e?{gDH7=E@5y*8XuVx^#ey} zH#&aR8J&@q(HV!&{!xzaCA~JpbZSjL+`W6dd(Xb_^Zweu{{H<>0M}7XVg#cK5-Lt$ zjG^j!wr+cd<#65D61tE9_oU(IrV$v9YwNkXA9#it+m&v3sJHbUB(6NjDVdRje{ltsSwo#!^RCii^dN^LKVd`(C#*yP$) zCoHvk6qgH0e1wk`XevIzMTVA#kV|8FodR4p2g#`YuiyorQ&s-=bJ`TxFJo} zGv((-)6gA5+Il7MNZ0IKHzP-(Kcv($Y@QE=V{tDXpL=iyQITf2y(*oS7WzE4*N=#Z zZEO>96alliq#&bW4)Y8{RgodNErQLQ)f6VDq#iCO*(7FhMa5@WU^ufa94F7$c*AXS zt0Y(21$BwSFf$14Pf7ildUF4|XmCeJPTYUaaOH&?&{xg!o!Wj3Shbk%+MX9`?MO@F z8op3)UB#EU!SLi5fz}fWhv>vG9g)4U74;In5(#Plb6>%IhFq6l|KCM}VXEI% zL%~Ca8{O#t-A4@C(M|Jgyrs7_F`SQ=`Z1?qjbW)vvEvn8D((B8?kermhbG|Z_DXmB zQ&)+ud!Q#3T@`4Qikc|NQP8CXWAy%-zV0E>-j|-gybCt}2b5>?zhPn*r(R)_KBx9R z&%DC)ue6_Gxs8>e_m710JvHecFhgU8Z*ZH?Bh=;gDZs_lhp%xVHM4_H-(YqJmnX+l z`VOwX!Qu{<=%C48_Axv9{)7wo89AB-^7KS{7DzJO!QJDcPxqql68h^t=m`|*j1jE# uS-VFoH|gRvf)XAiCTLW~BSg2bGFC}Wk$g;Y7Ee$id5z>c$wiVInD__B0;#M3 literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$BundleAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$BundleAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..cd317e1231c434f60dd8054b8df9d9b7dcd89218 GIT binary patch literal 891 zcmbVLO>Yx15PeS5EDb4z0!29@df?j^#3cwRO^FmKY9m0odv~WR7q1=J-irJrj+~G< z@B{c!h*^?`&ct-vGS8y*3)yNYLzH6D@&b=L=bQl^c?3rlq!# zyj4bKDk|d&*-u0CDvNJEE)s_{Bb$@W=0hHJe!hQDSw=4-fz~T+b$l&E>*4qUdFgU8 z@;E)EEH3MN7i(tTo#~vsoGhKc6<%8DA)Tno#3}ipogFOJe~EtuQ!#p-R*`}nm1PxG zYN)>&yK+|Lqds8;g3N=F12t2rHagCaTvUQNx>my4F5cj!O*J8(`bLdj>DLoXn6lm9AFU&p4(T&?pwJ^EBVoD#9t#WFe7x zp;a{1(ri=B`Yy$q9BYK*DC3TB%fd3a8xQ^N`5-9b471C&wXKvr9_H%>K!iC~ zfjA0)QCyLbkTHgFhEolZA-W~}&6H6QI%iluT}+ZujN+P%FEGJyW=mLBny>PrQ{l#< zy-xsU7r(Z^1kF4 zWs8%qy2vMIk_=~8%eGHUTo<08;8V8k)X?_m9yFZuUWoLOObLdPK|u613>ls_1$~NY zL~={6a)M#4Z6_`CfKDPy53bJVMR1HGHQ73>@|Xx1PgpG4Q~=Cbn&)v(!efS11Lyx= z-Ni7}s`8TXlvvzo{rK22Ts*Rh7_RSVmTO{3edQo%67mdF4KbZei%9Wynbn|p!-u|0 zgVmMBXMw~vD11S`SWq@mFBVi4)OLXwgKql2N2Bi$sqTx9Uws2M{yU_N@mJ`5gZ|eT zpy5z`c;+>Rf2I9Y-&So!=>H$G^A}Yue`AFD3=36jfz?@b(in)x&cDTl*vJkpzr*Mb zt`79X)E!)ZhshmGjmN&(!MDHAzM9o)#Ejtr>%bz-0{7|Hfd|M?8$`TBE!C?h_A}SQ zPe1t?c(0#jtWX|7J~Q=vF1JsrBJz>zB#;XbbBRWUI)n wwOGs1${i}IJFt!?kzVR;;CloW_6B~Sc8J;^sU5{nct-6FYBg#nsV$)QKZ;ry{{R30 literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$ComposeMaterialIconsLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$ComposeMaterialIconsLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..c16e2a9e15c3db06c939c47ae746112e2cf9d443 GIT binary patch literal 2253 zcmb_eU3c3w7=F}-y2%3D!e|+=&CtNouEdOwK}p$~bV~`ObS!PT;G!tD=4x}K9NEt3 zzk-{<;exYkeiVn-PSP4!=}PBwY)P-A_e; zcC;_-eh~Xog?2a4?&E3!1)Q@`EaGLn!f-R=<6#aw(KmwBkT!=xob=n;_l037P3A>I z?DK)tF$ues_9H&vPQaD#bRt8())uoFI7#~^1;~BTh-KgjQ=Zs8vQeAG1%|aP6&%=c zC?@fyiI~KgCgP+7l<=yBOGUhfIffVNB17ScjP~o^K)Qlq>&51zRzL}_7jYSHFw8xX zLC_EnL{ATd*HRlPmRA^dDrZUicjW#g^>qB(vL^zm1m*rMhULdPqS2lg278AX@b)J8 z-W#97UW&8=uHu>nyNI{(4#T&n0NOvGaEwn3^GULI`bim!jaYi3BisbE4A(2IXTk9Z zp_eWLUNQ%6? zKC-eoHquILjJ6z%n1s|2Rk=pc3Wi%J;WS~$zR?3pv2pH?J2i&fy7p-Q`8Gl1o4D5% zW}9~dlAQBJ%A83|4CTK=@;GgU3Gk9V`Hu7zk77gGet3@ktJy+MEN~OaheXw(vq_BH zgKS%0^Jk!>>2;Bn~34kv+g1bb%vFU_R}#i@%&-18J?d%wi+*{ zGudLW&?InWJU9i02{q4yVj`Diy4jOw3M{$X>3fq#S81HcXO?dK0`@cY7(PtK)Pil$ z_api($fax7Fr7$IE?K`KUpha;#iu9@F@IsU^yUy(o?>B$cb7_wL)`f3P*d_p0oK74 zwvA6n3f!W13ZLRLY7;vv)aLMcDy@yzWan0CW{G^B!WX!c%M-h=p@BU4zJ_&b7pT2U L?K19R1NpxIqGZiO literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$ComposeMaterialLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$ComposeMaterialLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..978cab4a3ce3e3f588611efc7caba2af078b715f GIT binary patch literal 2485 zcmb_eYje{^6g}%WC~;K?ZXl&E3kbzYXcW>yn>wY~1_y&_T0+w4bUGec+A0h3u1705 z&A)1A+R$ldI(+Vr>h#J+i80BLkbIEtY9D9so_qFQ{rlfv{{Z+5jT|xMHpPu4^i!wyw)>gV+~RR|4fe zovx~OM``}hp)&|4sJlw){*vu-3Nwxz-ZEgCcpImOh)L%heXHSJ7)I5W(u1g#o=D-X;z2w51A97zlOJg|4aKF#5kiHe9F|t%>wPHz<)7HT<6xS9;lJiDA8X9NNDp_fzUA{EtPO2SRe3MBZ7!qUeaT?~pPE!6ZZH_q@z-^7V@8TI8w}a1 z@<wd^viQhfXv-mq?*$c)7=L;ZZCjit&cff?O#} zsru*8q_6=7_tqo`YjopXUK5G$m;1T-prSFKP|jf1C8g_X;AqXYfigpRfb=&jnGBQr z6-@(o7;X-tAD%;oLlrrO!cb`#E>H&UF)R%@akT75Id+%vfgC$^;7vH&8yOTLE>c0u z(BBGSB~^`D8EVt-3cYXA*9~NQI*eU614EE4L(ue*3Xr&x(n z`7*wwUZ6xz;?y$PEWV<5hLB$!`Hq)$ literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$ComposeUiLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$ComposeUiLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..054ebac0be91d553fe9d340d4f6462afe4da37d6 GIT binary patch literal 3161 zcmb_e`&Sc36#gbW7GkOxQHp)AYFYzW7Taozp~yp_Xn06?6m7-L?zoI@c5?O+O8ayB z_q69&>}k*G@#p?gJ-wS`VNHXP!Vk%vo!Pzje&79O?)?4FAAbS(9FLPopiM!03LWTV zSeLG)S*~u{T+_=!6OPYaN4GUY_jOxZ+Emf=UET2SeqUR-!^_+;xnu0k(yVlMGlih| zpGk(!ap4Gmf?+nBKX#1V;JSh?hK;xJ-#MZrL=`()n4D7id=LfiBk$vDZGQz49mw2)99a}L+&`-WtceuGLlfx z7N&eQg*47FT(xz>AmpuJGHkvUK7xM&4CcCUp5b1NQDRuNql&1~Rf~Z`0`t_Tt}Lk) z?s`HxYF%NTDje0{=4!cCF|`<$Y$S<3ysMx;g^PHP;d-nj`x-TQ+2!PhylEuCXq=ap z6>^=9*7-Ew)+<5=G+E5%pXn7{vvtSP3cgFZ<_6=ewDP_{s?#k#9SGaxZYGL*5QC`r zfMIgUv3J$L;}KpjBqG9CC88Ap15g!QO5rlDFq~+L49OkgZ%>&OVQ_|}ljS6r!~i}@ z;bUB7xUeH^dz!EClB{rZ-kGbOHDe5G+2hc@LFq@-Q~6g#iPOgB#Qh+{wdc~Or!CX7 zxArw)Zbf`=)vK^oRaz3mxTfHf6h@#iJUD{T8l-SYP7Hk^*=yzSnB{YUFnNI+p=fF6 zX6Kv9@j#(V#b@+xPQi7C`^QX88bOIWes#YjF^bPp)DUhkD2{HedEt&}%MPx0;R}+7 zQ9Ch50+FPHW-NtU$kCy0xLo&1F*jQ&ChR3;S5^qDt1Z_DRGqIF&K>w3Axg^I!tfN_ zW_TFG*R&T!J!nCifz7G>4V~yMB)7J_ow79q6u8EI1DXY!Ej`Nnz-1c1=-GAT7tezdd>ewROMk z-+!g?N}ynaVJsHzEQ9~E=NK*?zUy#_&W;2a zCg_(A?<#Z$ZKp9^J?Vdvo^H@{g6#RB;g?`Te?r+DdV%hjIP)8Nex(JfKK-9Y8x5bJ zgFQwsS%zuM(5I8MHc4xYY$o0NJ1(T(-@}KmFtCSAPggp-hoM&(-NUCt>6?4_@)vrq z<}pkR%%)ad!X26g?$R%TSCa}FrqK#k5#BCWuts(O>-dK3FxgGA PqhueFoxme}*V+9q>FwGw literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$ComposeUiToolingLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$ComposeUiToolingLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..a7989f641128e90fcaa46854ac8d5df5c2e11f27 GIT binary patch literal 2584 zcmb_eT~`}L7=8wjg&1ucE7)r5D$xdtS^MD!1}T98(uNNkpyzmllileu?Pextb~nh+ z@CWE0&R<+qH*5k%= ziwuL)QpsqBVX;&@bBxOP))0mm?p0k^grQWv9ms~^MvBnZ#%{!l3JC2-MmO!YFrn1S zKByqHrLv|=2HS@m z@U~ODw-0t8xXEz&`2xz+Alg#wTDZ;dO*Z}G z`fA!wSF{%gf~fXPS3O!;)m=#IajO-`1jd1R?NR>cYQ)IZxY-b9gEslp=kU^F_4Yg_bkC2lu7wxFXl!$p*=%>St()W10IGV zv@p+5?X_7w4?%{D#~p(f78#~8-cQ&3NhgPuXO5WB6C1&W&XcSTE!-!fXEHd2mKf|_ zYO=7(a3|~je{h}DbTZqiYfjRYh2a+6U;4??wT1paq1jbh?;|@nas4;2Uui_8CUdf2 z-_!qR_#6YBcV|1_0>y&$JBADA_Hp4U3i}v6KU8>oA6K4YY#$#?6vp>){g*>e$z=)b z2V7x4Vv1IQFX-2Y3Z}^>alRzWFmviSH;#$(6UF)Y1#t#&rxShl;GJv^ReExhGU~$| i?hXvo0l9!B3=>8R_=@Zp*=4emxQ80qTUf!`;P5}Q8!9FM literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$DatastoreLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$DatastoreLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..878df4398d3af50846454359835de2cbf06f548d GIT binary patch literal 2224 zcmb_eU2_{X6g^5zHa4aorcEf&vJgX^G-N3sh2YS}PU;YFNT{3eXyjdGqjs(JNV_ii zSMXvO9+=L+6F-XKuI)`0Xb2(oj4kO(y1Mu1+#~<~$Irh2_z<5LFo8)6xguV`6vJMq zeaF|_3xvaa(vd0>TJgYfdBlUzcWNCIY3@e%zZ*@gi=I%PQ0`%atf4+Ex8lw}j0{sN zQpxBpL!;6>_Zijsy=hD{d{J{qk25f~ zRCaVA>|PN2QW?7wgzn>|0t$H1La~UKaDm}=CdMNSJkisF+>keiQcU~J(D#LAD5dkF zE)IBKhA|mCmF6Sf=T5+t@3bOKu~z4^2%P49ixT9%sK+w!gf6G&9-mR2#wCW;Z515a zu@Py$Lm<)|hd`VLKnX8fxKhMb%rHFH5E%+jWOPvT`qC8)+s_x1Y5^s@Qp7d9$}sap z20>js5Z$mZyiK(+B?$Z185SRh5sliO3ED>-@Y*Tf z?eQ(NhfFKr2Hvn>7x5=cEIJ-D zbi4D2)>bW)8NNJcXrUW-g^GstQotPEDdHw743^^lu1P9pvXT_?0>f30o|JZZJ@q|WcQ_Ia z+DoeBYQZC-Rn3a+Jjg{MD0CkBqdQ(DjZ!OK{b;h&T)vesn8;!b45cYSJaCG=Xr zjScI0JX- zN={@i>Bk~H-pOYIEP1}^_co1g&^WPAE!_GM><8*Gyq}Dz1tSwapqD>4T)T?N#ENps z`U&~c#Q`oqMQMQ9OVg#-2Dttda|67+P?{g$*7rxAl0OY#zv4Rk4IhyexI^Cwe2h=1 yP0m@SHiu7#*6Mgoc5a1c7AWQke1?0uJPG(J>c~^ literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$HiltLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$HiltLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..015df6d757493b03f8b4c03be0445046602bd95c GIT binary patch literal 2936 zcmb_eTUQfT6#fnu2jZZZqSRhw)K~*p25q&aq11qaXt+qYlqWiwISxlBXR^-Bgz~T2 zwJdhEYjyeTLsx%5`v=%y!!X2UjTfH)f8ILs-aCs zJ5Dhy`^q(4WjP)LgrML5PVnJpY!N3MTaLkGiBvn1Q*LEx*vbjoHyl$50e4<>y@^I%%edyy+- zFz)&Gv&;kGg|k*wxK=29S^s!5p9ttg3a2&bI=XO%;n6Xa>=n(>?r%u07$!~tg%mWj z#@3$Gk;Xd=*F4L%$>lfu$FQ7zN9dWPju=6w;42Pxl2KuF|FDDMp{pj{_RAIF z#cJCoe1}AyEl>n!qjHI>MXTh|PRiwBzHS6VW;bE>mrr*RT5yME<_tBlvgIYsZ^m~bkCU!O3(SoXIu{or84?wjMIgw5yp(<&?tl`Z zDbPD6(xubnU9{TiPYkPjtUkGlO;8o7B-(tEqQG#q-mng8oI^1ui5Sz8df0?# z1pyB<%rfMg66XIs8yI@_dpKx#Of+kj{`S5zTso`~_QW6TZPFT+7)F|O9xczP=WK_z zsps?_SQ*Z}mYBFq+15f2G?Eo}cAB-(oL*@3KSrzDw2sfu4-CEl8~7R8>cDe!zQEZZ z(EWYw;#c&42CXFHH?*@~(L*D3B;@I8EaEPmF&Z=Jo*!``{lOM4y+q#@GTj~N>=p)I zVt5O;2GV!7@cDP!5^H9$->JF%fpOXeCg|6Kd$>HLQDG3D{1ToY}gGKo$1cwqktW@Ev`yIfixN9PZ83XwuUcoHGzS6$! zYsU+??ev8$WW=>}0^4;WCs4j!?}m|f-004aqlw$R&!xwud)Oqa(ud`C-2Io4VRl_e z5#3^FR$6D?qqe+1hdG9C>aNSfP)OejL{~dn@X%7)>c)~12(3q2^{fHcp-|EqXAoLK zTG0Ww`a$dq8Cu;yxlgJlOuTBKSj0J;XSk7xaf*S*`{eud}#Kf?WfW6mG%9wA(!sBi3CZuJ!R@r_Y9gi5g z+kH%HYX-^;-<~lv<;FcOqqJU3Ea8J9uA#zUNXOp`lZu(CB!#>}5g&*ks!A#vKV4pR zRj;o?ZekT58mJaw<0Cr5Ohisv`bvkk*Rxxb>TfDd{cu~}A60iFDem%J@_ujXe6;v* zq#fjd#L3m%iHMmuPhw`GiG8gG1gf_0k2^Jn{HF5g{R=H3#l5)K<@%x14aj2pJlY&3 z!%+S^2aj`RPMF3$hC*BT(urbC&VKk0@2_VoH`&3_k$6Pf9NIf1!96FKNcWEN;(*g$ zV*#(-qC~Ddh-F0V-WQ>u1nN?%(Fqbv^BL|Og-9=%ZPGfIH${^1(u)tHnvjj5xGg2u zn}HLCJTyQTLp^)A|Lf{uxct1!$3UH7E#v)kl1suqO*SL!3&)n^3m~7a-M~y@ zMY&}BibCna5SN~zG{nNixzbxhTz!V6A>LmpEe~=1r>Upp;{myIxSBhU&&Uegq<;>d z;|pq&eb%VWTj)1&VzGo765*dz;!-+`$$Ke*pYx15PeQUHwoznf$|M)X$~o%`hvJ@RVk!Is)$OZpx&KbvohV-k-b|{eid9m z;=m8!Z*b(u5eYHLrZiuo)k-u&|@FN_H87 zdV4B(-}*9xnoYZ*&>x34oM?nP{ZD@7tR zJHzvO`<*xuJQh0Qox~~~`CAhysi`x({UTP*>kdq>Z=5Wm%5Y=E#Yw9~tUic@_%all zCX@`zZKdTw+UrXDMs#Dclp~omGTsce`Xy2`lsYQXB1tXb4=w@O8Rydr65!cT8#n*;0e*H~&9_?Llj)<@;Jo+l+;C(s@{8XiN!fMlTnt zmSHg~eu~ZmV=ZXazq{JLOJD>nIcyF{`r_&np^a0-ECr`hCeWEQ* zp4Nc_@;_)@#Z7`{&bfh=oU7hvls-;5|HLh_6aWAK literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$KotlinxCoroutinesLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$KotlinxCoroutinesLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..b840cebbd697216d80af03f7199a0580c1cd8eb6 GIT binary patch literal 2241 zcmb_eZFk!=6n>P3x-o%mVYF6Wf6rDI(S--=>ut~N)?k?pMg zSMa59_`um`eiVo6yw$);SGt@NOS+P;?tS#!NB-l_-+l-18SdH0VZuVbh}SU5u&qtt z28R2gaCuj{QpLh39=aZnd8h-o-i~6!z4-3lVB(JG3grvs?KjD)&3<_^Y5&W}Fu5d^ zjBhbCE3H%SQJdSI!W6?db;3&Dc<^wYe+;$9Z3;1bHADi41*V%Ahzq#LF#Sx1 zVM9C=9o-ZDnp*91d68kOavIpbr|?J6)A2u&9T7?;2>bUK7M|*uMmv5K?u z8|^2wwq~KsaQ~E{X)oyr75D4K#wP@t&spUwV{5rrXCCmyph&-`F{V1_EyIJ z2kZ9-3PL_eqC6vbO#Hlg96wWK>>Ax8XpQ?|*r_q(SF}&>pJ`D7-zJ^5FpqdUB#Rx0 zxIV~-q5O9y9_7p)@lE&)g-sbK9w&yJ{rD2^FJ9;@js(+mhCzoR(o6OxDV`^qGR=7Qzt5wZQjVdx zrj#%%A&(*vS)l8oo;~0HbpbJ)f6*0Wq0X?F@qRMlC3znwo00dKBa84{eXW;m|Em&^!$`Q1@is1 z%a};5D3`2XQ7D}`z`5rr9bo3{RO#IVTzZb#1AH)FnmfStpT?fjuL$H;aVd8XpOY21 zN&g(az?amf`z%tM$5(x8ZMY^ow?s4Z6mt$=<95D4ioT2n3KaV?R;Zn&_71fRxQkU3 F{sN-d$sqs$ literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$KotlinxLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$KotlinxLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..dd618137c1041b51ea4035996f248e5277bfedd8 GIT binary patch literal 2998 zcmb_eZC4XV6n-WI7Sgq1N{!Uot`aeTWz||K#!>?cMj|MI^!?;)cBjkeW|p%rApKSC zITd^CIX!;vkLu~&goPyKMH)Wr-r1Si=id9=mzlr+dGi;5+o+_FK#zi?ieB_FR9w&2 zZO^bAt{WRd7c$_UG#uSD0>g1_y-@Q5&oG0BFPjSw_y(62m*)07&AQ%pwj9>}Gs)0* zPe>8WFwEylUF*n?RTT6yeA|j-n%wtY&)2QGUJ^CW@C5hgU600oQ9gA-TS$M_am^Rm zMK^GSd^zWOZWsv3{pSAdLX0th6y8&ysyKu98J4=!(}~W|>uyQzG0dF;7bz&{i3~oc zB8?9ia*kn|@YG2!ty;SxjN5>GuT{!}y3{ zqTTN!e`ffpOV^Kt&-deFhR4l(64KV3I3YFH(`uol`tr4(J-4oHa?dC4wA}*pH6gWN zoogG-gw<+M#!ja22|iVzskn?Q3^!YN-78UxZ+M(w2u-I7jK?L{wxe82$LoBSuN#}f z4QaBLD?K+h4c#%Mt(OCjY|W3gGIJdI6Dm5x=Ch%2Ebe7vz56M8uIqRy$oapL|4!}S-9c2~80r@EH|RyF3kx*LUR zBhym2h0hh-R`CVyFg!a!qIIOgAvQ5&BC^*uqEm)1gu>!wZbnJVa4lCnC>{4Rbh-AN z_EK;8l3}q+(_AyGa~U-1C50*6RguR%21Oe7njck6Pj0NjkeqWZ%8IikB6KON*SNQ8 z)Et^QWAkAD2x0iKJ%rSRPwzm=Q;x;~<`%>7N+<)0az*%pj44RzHa+nv$67et|A!C; z$>6rO#Zc|q<~G329vzuorbc7(c@a@I(%f*^!8{p7nn5i}IvwX6!}qzb;4wp?CD#A% zTEZ}N(8WZ-6NWpj=Jf z7~R3dV1HWQ!Ogdr+QBp_8vJz+vte%{i%W^CD9|i0OHX9y97%=;cz9CuOeeZd=r;~P zPhy^QB(QM6+9O)IOV_moidakz(5QqZM0d9mmPrngd`fZ@&rl|Li{vWFDUxd#_!l5) Bz9awu literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$KotlinxSerializationLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$KotlinxSerializationLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..63cc8a1fd4dadeb7ae9c618287f5c6cce329c5e6 GIT binary patch literal 2244 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 literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$LifecycleViewmodelLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$LifecycleViewmodelLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..06f8908289e873ef85fd445f49e000754ce84cee GIT binary patch literal 2244 zcmb_eU31$+6g}&hC>DmcrX-ZoA{s-TG+306LU1Ut(>eqkQtBoQPeztD%C_s3XC*oK zU%@aF7#<+c{3wPi+e!p9gphj1y1RE*_iN8RtKa|l4-92xj_y&Fc_aija+jTi3mK35)B?yyPPKo869xcd(!!}N+! zBD%}athCPUqqeX!gBga;>#obgP$=J$qN^P(cxVOM>c)x^2(4Wm^sE8bp$L>U$sn|Z zvZ6h1^=0e}6xxKFAkOgwL(Si}o>k>PeG#-kc|ystT#A!|0Jn2uY4?{m#iO4oUV z?>Pez#H8$2T92K9V@pT*c01A(Yi%K0fzzySQi6`p8?lfc*X7jjv5(peE;6icDLJ&_ zkf-^M3X$eGD#U38DB&domy38AvkcEPLcG{EIi)kZUS0{o0W~H!SNWO zTiwUBw`QQs@WnYp3*5NJRW#}s6Z3ehh?}S|7|QXt!=z)TDoGv7{19w<&4@t(4p=1>{iME%|O#Q+)xk39o|S9yxdAX z?4%CHFAT>VLPm(BT+N+`5PIh{geKhB*TH~_tL+DqL5(55MxirYXc0KRjC)|+BhMG@?Wudk})$y9QPOsZQ&~?iZvPg_CLJ8lI`HcgQFv{OB@~An?%JuN2V0M z8F;be6qG<+sbGAPRHoSshK@s|m&`VCp39pe$$0+X52Tua zj-j}r6xVCg2}2$lpbMg&J>dU!1uBU<=f&D-uhIf-WN#uT{=X>-u zkRR<`#Z;n2xn%r|Lg~T*E*+wDfVqn^rK<*w zKw97q{d4#bACXM_ER)RRDmcrX;k`B8Z_*8Y0R^Avl!SX&nMiQ|cx>nzgi5wv|_&mE@9t z1uur-f$1~+0QfabuVl+np&^9SGxpuRyL&&*o_p87{q@VQ06xN(CJLA`FkQk6m|@rp zv}b#oyS}h_U)oYdLM!gu4v)AWcy_%TMw&a(t?x$*H$`74S19M8N!makRN8U(A4-Oq zHK}BDgP~b%o!Uojac>s03}4k9M}(nNp5@D~=30u-3bfUY6(tZ__jS;-21182P}Vqu z(2~lE_J!5=V^6Bk>iU86aK(g)7Y&q3cnL2vT+78c!N3)LEyxU6vnj=F+zLETXohmO zE*fH=4`dLNvRiFE-~(>^TzPgo(iCfLF^|A;*0(7^?ukY$eOKs8=J(J?Z5C%4)_0VD zV8x-x@=bxra!i3Z4uCRVF>tmTx6Jg zBz?aj?uuS85bl=ROu4+uuvQ`Mx9m#B0U)r*(zTycV4 zKL~}1WxQu#r34%AKaCSlt3J@7?e^?eR`|_8(>UBxcSeQXNb0(Bdt!LB@nF<4=rHvp zM++ViA+H}t$fOnabub_-wS8wis4+}$1TLLF(;_b1j(c69@A0lr8q*We#wZbn%G1<4 z%9xoEOt=iiw)7N_Vok=r`w!>W@&%iC;5w4`sU?T@Hg(<}_p^?@9k{VC$k(`U*KSZE z7w*O?B2w?kP*MVQrGnAL5lnMA${dDBhs-v$I7c*PlJUa7U&KnnF^1BXQbKR|JPbu> zfZl_8j%EMv#bG%AtT)F%onbX+{bZe%NI6M1*U#sVth#gQN}luvn#8SK1ScRa!^NYi zORZy>-tFX5083tO`n^W8%QR2)GfP*00{f9h3?C$Ok|_L6zaP@0Kb`Jf$5f(4rEL6+ zV)@Jv=N_Xx#QfRW^6NufdW?l3-dQRy4srE|iKXQK0t$cNQsGa0Oj_VNeGB*mpOQ@c wtdg9@XQ{R}-jiQjqm?C!xq#2{#dMK+_c|IVQta#4Ah|&DCdp;o!X}DO0KXZ*ivR!s literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$PluginAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$PluginAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..ddddb5694b0f7bb785138b4cfd05b583ef08762a GIT binary patch literal 1970 zcmb_dZBNrs6n^dsl+_|S0YN|nrjGGaUqKy`Opr*J2*Hr}vFk4NN@w-Jm;MI+;hKv|L_UGE!@|TfTE&BM=RPGo_NwWY-yGp zZkT0Z2shx;H66n;1Jm(rBVY6bXo{wsQ}9hVqd zo(m_?sH`J8Mv-RFEy>M*M-*U~&JlL8j|iP1ooT`)v2b13t{GG$8Lu>9GFxA-^5IQ4Dn2)&+>V<; zZZ1azrD&GJcr{Y06ku3ufcbYCQ5qrAAs-l4PwqdKB$SA@?p3747e!d((cia`sqk#+ z%$Ho3%X!E2eeSE6X2{ofjuW+3hK{Jt)jp}>F0rZJZS%Ec=!w6SM5_qo=uR| z#PI|@BMGF!{y|zQymTa6!NT{1{#R+VM!G_BGCMwT0G9m-^;z~UlJs>R;M_jCXsWkv z>cT$y_sD=DL;n<70A&wt$}99KuQ5S7^-N?5ICMWml95!isiAimesg3P;zN0lahgeB zf<}{ZMwerZKGzvd!64HRX^>=y)Jlo*GL#$ix5=?w-(D8mG9 WV+KiT$#-y%q((AFvX|s6l0N`senp-D literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$RoomLibraryAccessors.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$RoomLibraryAccessors.class new file mode 100644 index 0000000000000000000000000000000000000000..d8c07466809217283352693362fade8ea7a038dc GIT binary patch literal 2465 zcmb_eZC4vb6n-X&Y!Xu2#tK%Yt|i()k+oW1Fo;cPgOpGzDflsNcBjjf%}mbhZVLZO zzo5qto__Xk_yhD0*wedtfz(oHq&X*!+gF}dZU&*Yo$$_HZ{s#^bLn#F>{m&u^nRfpHD3@i zj4cW&!X<`kv36z~rJ3zC(hPUYj>CgMNYC^|Q`=hbz*O37Mv?*u%!gXF%nsLqP}1y2 z5ST)m;SM+3e&h)mm`z_fyYpFOF>WB2!#TXkaAU~FLkwKr)|}LkHj6?W%xlW?xMs)? z_IZWx*d3uF5;lvqM|Q`yd|P@}J=ElDX=WIK)3mQsfVRggk?>uv3j@1HHcDw+V7Rp* z{e3eE_#oac5Q7-IK%53Z9&Z`Al*8MYV0f)AGGrf%aHs5cgu@v&UN0u4Eb@3Khs$`E zVdAmy{R-dYE!E-fs$A)Ed4XZ8cox`yB=-l7WakZg#G&rbGs^}Rl^PZ#vupX z#sKd|KMRd6)3UgN4-A+&e2A+IKa4=M|4`v2J~2$jU~jeKGUh9haCx0OF=-jD6<3d= z;}JtQnvdvg$v}Z&?ToG|Cu(sScIzdJX?&c+H53^PX?t5iTrtUFT*$Kw=d@C-c}KO{ z!sj}RIecPZJ_ie*KJSO!EqJ8^%WYY;LCsf{rg^X`@AqoD5|?yglXUiu?DzTvU86?i zXl{qZ!Y@x_Vch@PT6G9OZQburDC3_oq`Us^hI?t;WXN?_I+7vLf+4l6TpG^Th#>c( zR+H-ocGD-xxW~igevAx-=LvbdHL9Ee?YPU3sS8iqVWdghPp@!)akz|Q3$_l$Lu%B4 zwNCxGW&49ZzOLNJ=VYtj%}YxqhRd71n6^bAD1x$-s+Uf}abk!_M=sK(F^Y06+#}Cv z(pNx>I<-TGS1G>?(pq_=|qO!q;>sK6?wvSc*d4_zju-`2$>hg8Ts{FQoJD9boDSrVsGZ zY<}hd*MC0L6#uJ0;%`hP{=ouCfp6%WKnaU9#&*7?kzr|MJ2#H8^Do(XdZL~0Mz-_$ zi*}OZm`dhOu#+OR;wa1gGsCe~XlIskkiatTq%!nkRq;JCl#41>X`H6o3Sx5G!wA?sz z=FC@s3rHOJ0DLIKY#!A%u>he+&e)#cc>MRw{`~d*2Y>~v4}WNa&CUuE!%DDBmq^m`HOkTG?)Iltn{?H4%C{tF)^0&h!hRjZ|T0%CLV? zhB8`W@MbDK(HmNA$(qpaddKKMg^Mo-<8@E<>D{@0~ErnTCnr!npTo0PQ49#+&yv^>#id}>u z=ZkI%3^!*gZ}=8>10MQrHPSNl3$wi!>AP{k!6Ak;_ZtrK6wzy^ysYXD#uzf5(qb*z zc5t}0sZ}$Qp)d|67_v3Gw;|DmgJTQ>uVoN9IKeO;TTl3w^m#;2(UHNyNqUV<6$LVM zaGFltG<51&3KYm!!rSoz3N+0y6859#DZW;5Rx=DkMrg?c`K}e7c1o%yNcRe*_M}lN2DpkM91n=mlCF}wU)Z=Q`Zcg8V9O$)nyo?sRfPWKO=P+ z4v|&et8T8Un%WbqGFEiz&qaDUEnK_eFEY67}ygGMb-Apu>pLE{!^ zB>`QxK}Rgm(*(3&gN|CDmkH>G4LWXtyaaU922EO^dIGv-gHBnXw+ZOB4LW0i-Y1|t yHfYKMeMmreZO}Oj^f3VyY|sS@^l2ALVX;-Z_pn6&c`D)*?xTn-waqfh$o>XqGPDl> literal 0 HcmV?d00001 diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock.class b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock.class new file mode 100644 index 0000000000000000000000000000000000000000..408636a14fa4b594b3f261a5266cf61720400715 GIT binary patch literal 9517 zcmb_i`F|6~75`2EFDOd_ZelQrK@hhXLr_C=lo%3h6O6$aVjBaciMx{4Vqvwbu2u%8 zZAkC5=|Os?_kCYU8$n9il-_OHr1zEH_x&&Q)9-3mlC|1J)+#@kuV#1lJMX=DGxOdX z9{=C@#{gW9|Hg0$7D!kqV-eZ}`b{g7$XH5RR})H3OK66zT85%0Qi`qUW+u^}%-fcd zvTr-(zSybeR3oh#so7n8YFe`bZQC?Mvu_cit!JbW-A;8{Dd_g3YUMT47<32e^M97J z%o#1MT8RVR4{xlxj#)FU>WTfy<7&zd>r+ulv29CB7Hl=27|v!3wvyD<{>rn)pIf#z zO`Y?JbY4#kDmf*o>6$$|YTAlTWezA-UbXr*OfJDFzhu zmZ_yrxdPAjmz9WNDV8~ov|M0UN}lbWA>#^MDX>OYQYqRdY302ub-Q}?$k>2hfvY^df;tQA zi>gu(9ktmM-2?ZUwyqfg3w5KbP(sGDab48|L;APifgy}k>p9Uqa73F{Q?n^Ozyr6q zirpyVCOo(5fuUct;DMo>RPJVOMiD)5RGHB-r4yvy54XD7ZI^KiZWUPT`C<4c0^?D= zF`Sh8^+#V}W2Tv{*KCKY*-ja^VOMp91$Ay=g$2=3o81CK5ogPbTqWjr5u2uNlr zhUCO`*T~9=3yLwFIh&I40w@B@t8t|lLkisLC#g(dwe!V-P=`MyBMntxWhx}p6xb0y z%>07Y7!D)jxXZDi=siet|A=CwH4A*0>=`+(%qR(6F*1p9rh!JLuV#mC#J-Pd zo03rn3YyNmw7WcRbqt!~C0vmE4ShCV$g5?2^Nu0PI+hI4$N;BtkA#=Xco|+UFxSmm z7EvH}QnQcsr)RVj_m%xmuTA=5IE`1zcokkv&pWB<`hYs7X3ZHjJ!}k>Dhyi%4)(NS z_CplEYh zC}KE+H_Lbn-pUitP%;Nuun<_#vtd$T;UH@%0+)}_preIsQneVXiFcaf)Rlrvj50E;t{gAw<@(wi zeXi?5XLp|60EE&^+gR)ijo%S&(O zo=p#N)7?YZMvXqR~ zJL$T{oh1BF;83eFcu_#T1o4UlAzdW=MBr$|@x5g;u3DO+Yj*|K$(Xdyr<;VI3mk4u zjzQBh3pPWfe7zyodP0Qvk?<>?N)aV+_LYlm2dgjMLBemMdx5tT9@HjGlM#2OUio;V zE)sqpy#QPxuOGNG^qqu1MfW?8b)Uj(PkP=k3v&Te-aVgg688lV)?7x zxmPS9ui;9_TdNZCmZyZg94R615=zLbdkI;iE+OljC1iD|ge~VZ5-`wfLO(G z+xYa!-i@2C?OfQo=p00EZxK@OqgZ;R_hCrqaCs5!Y<76fl|^*2+2u9Y6cJ~$+iO0n zi1lo4^qSWev6;;+Ui11QZeVk(*X%1|8=E`4=0FjHYz{fiVgBtqhue#o;G@INqvw?$ z6Yu0-@*Jj%(D*t#=L@rl+(Xnz;O+ePW?aU9*VCpeu?(G9gH_nfi_Pt{=?J=T6svKZ zPiGOwy_|)2@ow-u?fe9K@BqJTBhNcZZ13c|1&+;lyRm>zfpzWnBbaG_@mbt`0jJO6 z70VX4-+LCXy?`@k@g@q`{$S}#M-JzIGJx~dg)MkDf1$$u9{v`1FW%QId#9g$8`-x9 zvcDf6XqG+hXCET_?m+er;zP}{ulKW$k$pUn{loZ3v+SGw?01m;&Or8$;$zLS-{5CI zMs_Wb{p0vVv+Uda?0K@=f$X2ere7N2WY5UtANE{!uB=KerI9>hZ&!!Jm#O5h6e07dvb1-b-ZsI0Ar*)H<$DX#dX z-099@2|9@9h+V`-h~3055;qdh6Soi_C2l2tiMWIKW#SO=G2&t3SBP2S1>$LZ6<;Ub zNBjoy4Dp-9Z}I(ih~FiCkNAD!lf)koe? b8ƒ + M๎ˆclasses‹aภ:0ห?ฆ†}ชŒญกˆsources PTีีืฒ๋iŸ›P \ No newline at end of file diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/sources/org/gradle/accessors/dm/LibrariesForLibs.java b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/sources/org/gradle/accessors/dm/LibrariesForLibs.java new file mode 100644 index 0000000..32459fd --- /dev/null +++ b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/sources/org/gradle/accessors/dm/LibrariesForLibs.java @@ -0,0 +1,775 @@ +package org.gradle.accessors.dm; + +import org.gradle.api.NonNullApi; +import org.gradle.api.artifacts.MinimalExternalModuleDependency; +import org.gradle.plugin.use.PluginDependency; +import org.gradle.api.artifacts.ExternalModuleDependencyBundle; +import org.gradle.api.artifacts.MutableVersionConstraint; +import org.gradle.api.provider.Provider; +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.ProviderFactory; +import org.gradle.api.internal.catalog.AbstractExternalDependencyFactory; +import org.gradle.api.internal.catalog.DefaultVersionCatalog; +import java.util.Map; +import org.gradle.api.internal.attributes.ImmutableAttributesFactory; +import org.gradle.api.internal.artifacts.dsl.CapabilityNotationParser; +import javax.inject.Inject; + +/** + * A catalog of dependencies accessible via the {@code libs} extension. + */ +@NonNullApi +public class LibrariesForLibs extends AbstractExternalDependencyFactory { + + private final AbstractExternalDependencyFactory owner = this; + private final AndroidxLibraryAccessors laccForAndroidxLibraryAccessors = new AndroidxLibraryAccessors(owner); + private final ComposeLibraryAccessors laccForComposeLibraryAccessors = new ComposeLibraryAccessors(owner); + private final DatastoreLibraryAccessors laccForDatastoreLibraryAccessors = new DatastoreLibraryAccessors(owner); + private final HiltLibraryAccessors laccForHiltLibraryAccessors = new HiltLibraryAccessors(owner); + private final KotlinxLibraryAccessors laccForKotlinxLibraryAccessors = new KotlinxLibraryAccessors(owner); + private final LifecycleLibraryAccessors laccForLifecycleLibraryAccessors = new LifecycleLibraryAccessors(owner); + private final NavigationLibraryAccessors laccForNavigationLibraryAccessors = new NavigationLibraryAccessors(owner); + private final RoomLibraryAccessors laccForRoomLibraryAccessors = new RoomLibraryAccessors(owner); + private final VersionAccessors vaccForVersionAccessors = new VersionAccessors(providers, config); + private final BundleAccessors baccForBundleAccessors = new BundleAccessors(objects, providers, config, attributesFactory, capabilityNotationParser); + private final PluginAccessors paccForPluginAccessors = new PluginAccessors(providers, config); + + @Inject + public LibrariesForLibs(DefaultVersionCatalog config, ProviderFactory providers, ObjectFactory objects, ImmutableAttributesFactory attributesFactory, CapabilityNotationParser capabilityNotationParser) { + super(config, providers, objects, attributesFactory, capabilityNotationParser); + } + + /** + * Group of libraries at androidx + */ + public AndroidxLibraryAccessors getAndroidx() { + return laccForAndroidxLibraryAccessors; + } + + /** + * Group of libraries at compose + */ + public ComposeLibraryAccessors getCompose() { + return laccForComposeLibraryAccessors; + } + + /** + * Group of libraries at datastore + */ + public DatastoreLibraryAccessors getDatastore() { + return laccForDatastoreLibraryAccessors; + } + + /** + * Group of libraries at hilt + */ + public HiltLibraryAccessors getHilt() { + return laccForHiltLibraryAccessors; + } + + /** + * Group of libraries at kotlinx + */ + public KotlinxLibraryAccessors getKotlinx() { + return laccForKotlinxLibraryAccessors; + } + + /** + * Group of libraries at lifecycle + */ + public LifecycleLibraryAccessors getLifecycle() { + return laccForLifecycleLibraryAccessors; + } + + /** + * Group of libraries at navigation + */ + public NavigationLibraryAccessors getNavigation() { + return laccForNavigationLibraryAccessors; + } + + /** + * Group of libraries at room + */ + public RoomLibraryAccessors getRoom() { + return laccForRoomLibraryAccessors; + } + + /** + * Group of versions at versions + */ + public VersionAccessors getVersions() { + return vaccForVersionAccessors; + } + + /** + * Group of bundles at bundles + */ + public BundleAccessors getBundles() { + return baccForBundleAccessors; + } + + /** + * Group of plugins at plugins + */ + public PluginAccessors getPlugins() { + return paccForPluginAccessors; + } + + public static class AndroidxLibraryAccessors extends SubDependencyFactory { + private final AndroidxActivityLibraryAccessors laccForAndroidxActivityLibraryAccessors = new AndroidxActivityLibraryAccessors(owner); + private final AndroidxCoreLibraryAccessors laccForAndroidxCoreLibraryAccessors = new AndroidxCoreLibraryAccessors(owner); + + public AndroidxLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Group of libraries at androidx.activity + */ + public AndroidxActivityLibraryAccessors getActivity() { + return laccForAndroidxActivityLibraryAccessors; + } + + /** + * Group of libraries at androidx.core + */ + public AndroidxCoreLibraryAccessors getCore() { + return laccForAndroidxCoreLibraryAccessors; + } + + } + + public static class AndroidxActivityLibraryAccessors extends SubDependencyFactory { + + public AndroidxActivityLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for compose with androidx.activity:activity-compose coordinates and + * with version reference activityCompose + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getCompose() { + return create("androidx.activity.compose"); + } + + } + + public static class AndroidxCoreLibraryAccessors extends SubDependencyFactory { + + public AndroidxCoreLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for ktx with androidx.core:core-ktx coordinates and + * with version reference coreKtx + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getKtx() { + return create("androidx.core.ktx"); + } + + } + + public static class ComposeLibraryAccessors extends SubDependencyFactory { + private final ComposeMaterialLibraryAccessors laccForComposeMaterialLibraryAccessors = new ComposeMaterialLibraryAccessors(owner); + private final ComposeUiLibraryAccessors laccForComposeUiLibraryAccessors = new ComposeUiLibraryAccessors(owner); + + public ComposeLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for bom with androidx.compose:compose-bom coordinates and + * with version reference composeBom + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getBom() { + return create("compose.bom"); + } + + /** + * Dependency provider for material3 with androidx.compose.material3:material3 coordinates and + * with no version specified + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getMaterial3() { + return create("compose.material3"); + } + + /** + * Group of libraries at compose.material + */ + public ComposeMaterialLibraryAccessors getMaterial() { + return laccForComposeMaterialLibraryAccessors; + } + + /** + * Group of libraries at compose.ui + */ + public ComposeUiLibraryAccessors getUi() { + return laccForComposeUiLibraryAccessors; + } + + } + + public static class ComposeMaterialLibraryAccessors extends SubDependencyFactory { + private final ComposeMaterialIconsLibraryAccessors laccForComposeMaterialIconsLibraryAccessors = new ComposeMaterialIconsLibraryAccessors(owner); + + public ComposeMaterialLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Group of libraries at compose.material.icons + */ + public ComposeMaterialIconsLibraryAccessors getIcons() { + return laccForComposeMaterialIconsLibraryAccessors; + } + + } + + public static class ComposeMaterialIconsLibraryAccessors extends SubDependencyFactory { + + public ComposeMaterialIconsLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for extended with androidx.compose.material:material-icons-extended coordinates and + * with no version specified + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getExtended() { + return create("compose.material.icons.extended"); + } + + } + + public static class ComposeUiLibraryAccessors extends SubDependencyFactory implements DependencyNotationSupplier { + private final ComposeUiToolingLibraryAccessors laccForComposeUiToolingLibraryAccessors = new ComposeUiToolingLibraryAccessors(owner); + + public ComposeUiLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for ui with androidx.compose.ui:ui coordinates and + * with no version specified + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider asProvider() { + return create("compose.ui"); + } + + /** + * Dependency provider for graphics with androidx.compose.ui:ui-graphics coordinates and + * with no version specified + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getGraphics() { + return create("compose.ui.graphics"); + } + + /** + * Group of libraries at compose.ui.tooling + */ + public ComposeUiToolingLibraryAccessors getTooling() { + return laccForComposeUiToolingLibraryAccessors; + } + + } + + public static class ComposeUiToolingLibraryAccessors extends SubDependencyFactory implements DependencyNotationSupplier { + + public ComposeUiToolingLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for tooling with androidx.compose.ui:ui-tooling coordinates and + * with no version specified + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider asProvider() { + return create("compose.ui.tooling"); + } + + /** + * Dependency provider for preview with androidx.compose.ui:ui-tooling-preview coordinates and + * with no version specified + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getPreview() { + return create("compose.ui.tooling.preview"); + } + + } + + public static class DatastoreLibraryAccessors extends SubDependencyFactory { + + public DatastoreLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for preferences with androidx.datastore:datastore-preferences coordinates and + * with version reference datastore + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getPreferences() { + return create("datastore.preferences"); + } + + } + + public static class HiltLibraryAccessors extends SubDependencyFactory { + private final HiltNavigationLibraryAccessors laccForHiltNavigationLibraryAccessors = new HiltNavigationLibraryAccessors(owner); + + public HiltLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for android with com.google.dagger:hilt-android coordinates and + * with version reference hilt + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getAndroid() { + return create("hilt.android"); + } + + /** + * Dependency provider for compiler with com.google.dagger:hilt-android-compiler coordinates and + * with version reference hilt + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getCompiler() { + return create("hilt.compiler"); + } + + /** + * Group of libraries at hilt.navigation + */ + public HiltNavigationLibraryAccessors getNavigation() { + return laccForHiltNavigationLibraryAccessors; + } + + } + + public static class HiltNavigationLibraryAccessors extends SubDependencyFactory { + + public HiltNavigationLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for compose with androidx.hilt:hilt-navigation-compose coordinates and + * with version reference hiltNavigationCompose + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getCompose() { + return create("hilt.navigation.compose"); + } + + } + + public static class KotlinxLibraryAccessors extends SubDependencyFactory { + private final KotlinxCoroutinesLibraryAccessors laccForKotlinxCoroutinesLibraryAccessors = new KotlinxCoroutinesLibraryAccessors(owner); + private final KotlinxSerializationLibraryAccessors laccForKotlinxSerializationLibraryAccessors = new KotlinxSerializationLibraryAccessors(owner); + + public KotlinxLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Group of libraries at kotlinx.coroutines + */ + public KotlinxCoroutinesLibraryAccessors getCoroutines() { + return laccForKotlinxCoroutinesLibraryAccessors; + } + + /** + * Group of libraries at kotlinx.serialization + */ + public KotlinxSerializationLibraryAccessors getSerialization() { + return laccForKotlinxSerializationLibraryAccessors; + } + + } + + public static class KotlinxCoroutinesLibraryAccessors extends SubDependencyFactory { + + public KotlinxCoroutinesLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for android with org.jetbrains.kotlinx:kotlinx-coroutines-android coordinates and + * with version reference coroutines + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getAndroid() { + return create("kotlinx.coroutines.android"); + } + + } + + public static class KotlinxSerializationLibraryAccessors extends SubDependencyFactory { + + public KotlinxSerializationLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for json with org.jetbrains.kotlinx:kotlinx-serialization-json coordinates and + * with version reference serialization + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getJson() { + return create("kotlinx.serialization.json"); + } + + } + + public static class LifecycleLibraryAccessors extends SubDependencyFactory { + private final LifecycleRuntimeLibraryAccessors laccForLifecycleRuntimeLibraryAccessors = new LifecycleRuntimeLibraryAccessors(owner); + private final LifecycleViewmodelLibraryAccessors laccForLifecycleViewmodelLibraryAccessors = new LifecycleViewmodelLibraryAccessors(owner); + + public LifecycleLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Group of libraries at lifecycle.runtime + */ + public LifecycleRuntimeLibraryAccessors getRuntime() { + return laccForLifecycleRuntimeLibraryAccessors; + } + + /** + * Group of libraries at lifecycle.viewmodel + */ + public LifecycleViewmodelLibraryAccessors getViewmodel() { + return laccForLifecycleViewmodelLibraryAccessors; + } + + } + + public static class LifecycleRuntimeLibraryAccessors extends SubDependencyFactory { + + public LifecycleRuntimeLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for compose with androidx.lifecycle:lifecycle-runtime-compose coordinates and + * with version reference lifecycle + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getCompose() { + return create("lifecycle.runtime.compose"); + } + + /** + * Dependency provider for ktx with androidx.lifecycle:lifecycle-runtime-ktx coordinates and + * with version reference lifecycle + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getKtx() { + return create("lifecycle.runtime.ktx"); + } + + } + + public static class LifecycleViewmodelLibraryAccessors extends SubDependencyFactory { + + public LifecycleViewmodelLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for compose with androidx.lifecycle:lifecycle-viewmodel-compose coordinates and + * with version reference lifecycle + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getCompose() { + return create("lifecycle.viewmodel.compose"); + } + + } + + public static class NavigationLibraryAccessors extends SubDependencyFactory { + + public NavigationLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for compose with androidx.navigation:navigation-compose coordinates and + * with version reference navigationCompose + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getCompose() { + return create("navigation.compose"); + } + + } + + public static class RoomLibraryAccessors extends SubDependencyFactory { + + public RoomLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for compiler with androidx.room:room-compiler coordinates and + * with version reference room + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getCompiler() { + return create("room.compiler"); + } + + /** + * Dependency provider for ktx with androidx.room:room-ktx coordinates and + * with version reference room + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getKtx() { + return create("room.ktx"); + } + + /** + * Dependency provider for runtime with androidx.room:room-runtime coordinates and + * with version reference room + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getRuntime() { + return create("room.runtime"); + } + + } + + public static class VersionAccessors extends VersionFactory { + + public VersionAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); } + + /** + * Version alias activityCompose with value 1.9.0 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getActivityCompose() { return getVersion("activityCompose"); } + + /** + * Version alias agp with value 8.4.1 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getAgp() { return getVersion("agp"); } + + /** + * Version alias composeBom with value 2024.06.00 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getComposeBom() { return getVersion("composeBom"); } + + /** + * Version alias coreKtx with value 1.13.1 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getCoreKtx() { return getVersion("coreKtx"); } + + /** + * Version alias coroutines with value 1.8.1 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getCoroutines() { return getVersion("coroutines"); } + + /** + * Version alias datastore with value 1.1.1 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getDatastore() { return getVersion("datastore"); } + + /** + * Version alias hilt with value 2.51.1 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getHilt() { return getVersion("hilt"); } + + /** + * Version alias hiltNavigationCompose with value 1.2.0 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getHiltNavigationCompose() { return getVersion("hiltNavigationCompose"); } + + /** + * Version alias kotlin with value 2.0.0 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getKotlin() { return getVersion("kotlin"); } + + /** + * Version alias ksp with value 2.0.0-1.0.21 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getKsp() { return getVersion("ksp"); } + + /** + * Version alias lifecycle with value 2.8.2 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getLifecycle() { return getVersion("lifecycle"); } + + /** + * Version alias navigationCompose with value 2.7.7 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getNavigationCompose() { return getVersion("navigationCompose"); } + + /** + * Version alias room with value 2.6.1 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getRoom() { return getVersion("room"); } + + /** + * Version alias serialization with value 1.7.1 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getSerialization() { return getVersion("serialization"); } + + } + + public static class BundleAccessors extends BundleFactory { + + public BundleAccessors(ObjectFactory objects, ProviderFactory providers, DefaultVersionCatalog config, ImmutableAttributesFactory attributesFactory, CapabilityNotationParser capabilityNotationParser) { super(objects, providers, config, attributesFactory, capabilityNotationParser); } + + } + + public static class PluginAccessors extends PluginFactory { + private final AndroidPluginAccessors paccForAndroidPluginAccessors = new AndroidPluginAccessors(providers, config); + private final KotlinPluginAccessors paccForKotlinPluginAccessors = new KotlinPluginAccessors(providers, config); + + public PluginAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); } + + /** + * Plugin provider for hilt with plugin id com.google.dagger.hilt.android and + * with version reference hilt + *

+ * This plugin was declared in catalog libs.versions.toml + */ + public Provider getHilt() { return createPlugin("hilt"); } + + /** + * Plugin provider for ksp with plugin id com.google.devtools.ksp and + * with version reference ksp + *

+ * This plugin was declared in catalog libs.versions.toml + */ + public Provider getKsp() { return createPlugin("ksp"); } + + /** + * Group of plugins at plugins.android + */ + public AndroidPluginAccessors getAndroid() { + return paccForAndroidPluginAccessors; + } + + /** + * Group of plugins at plugins.kotlin + */ + public KotlinPluginAccessors getKotlin() { + return paccForKotlinPluginAccessors; + } + + } + + public static class AndroidPluginAccessors extends PluginFactory { + + public AndroidPluginAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); } + + /** + * Plugin provider for android.application with plugin id com.android.application and + * with version reference agp + *

+ * This plugin was declared in catalog libs.versions.toml + */ + public Provider getApplication() { return createPlugin("android.application"); } + + } + + public static class KotlinPluginAccessors extends PluginFactory { + + public KotlinPluginAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); } + + /** + * Plugin provider for kotlin.android with plugin id org.jetbrains.kotlin.android and + * with version reference kotlin + *

+ * This plugin was declared in catalog libs.versions.toml + */ + public Provider getAndroid() { return createPlugin("kotlin.android"); } + + /** + * Plugin provider for kotlin.compose with plugin id org.jetbrains.kotlin.plugin.compose and + * with version reference kotlin + *

+ * This plugin was declared in catalog libs.versions.toml + */ + public Provider getCompose() { return createPlugin("kotlin.compose"); } + + /** + * Plugin provider for kotlin.serialization with plugin id org.jetbrains.kotlin.plugin.serialization and + * with version reference kotlin + *

+ * This plugin was declared in catalog libs.versions.toml + */ + public Provider getSerialization() { return createPlugin("kotlin.serialization"); } + + } + +} diff --git a/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/sources/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock.java b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/sources/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock.java new file mode 100644 index 0000000..7f4717c --- /dev/null +++ b/.gradle/8.7/dependencies-accessors/4d36d099e6cbda31bf86da5ce95a8407329b9417/sources/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock.java @@ -0,0 +1,1023 @@ +package org.gradle.accessors.dm; + +import org.gradle.api.NonNullApi; +import org.gradle.api.artifacts.MinimalExternalModuleDependency; +import org.gradle.plugin.use.PluginDependency; +import org.gradle.api.artifacts.ExternalModuleDependencyBundle; +import org.gradle.api.artifacts.MutableVersionConstraint; +import org.gradle.api.provider.Provider; +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.ProviderFactory; +import org.gradle.api.internal.catalog.AbstractExternalDependencyFactory; +import org.gradle.api.internal.catalog.DefaultVersionCatalog; +import java.util.Map; +import org.gradle.api.internal.attributes.ImmutableAttributesFactory; +import org.gradle.api.internal.artifacts.dsl.CapabilityNotationParser; +import javax.inject.Inject; + +/** + * A catalog of dependencies accessible via the {@code libs} extension. + */ +@NonNullApi +public class LibrariesForLibsInPluginsBlock extends AbstractExternalDependencyFactory { + + private final AbstractExternalDependencyFactory owner = this; + private final AndroidxLibraryAccessors laccForAndroidxLibraryAccessors = new AndroidxLibraryAccessors(owner); + private final ComposeLibraryAccessors laccForComposeLibraryAccessors = new ComposeLibraryAccessors(owner); + private final DatastoreLibraryAccessors laccForDatastoreLibraryAccessors = new DatastoreLibraryAccessors(owner); + private final HiltLibraryAccessors laccForHiltLibraryAccessors = new HiltLibraryAccessors(owner); + private final KotlinxLibraryAccessors laccForKotlinxLibraryAccessors = new KotlinxLibraryAccessors(owner); + private final LifecycleLibraryAccessors laccForLifecycleLibraryAccessors = new LifecycleLibraryAccessors(owner); + private final NavigationLibraryAccessors laccForNavigationLibraryAccessors = new NavigationLibraryAccessors(owner); + private final RoomLibraryAccessors laccForRoomLibraryAccessors = new RoomLibraryAccessors(owner); + private final VersionAccessors vaccForVersionAccessors = new VersionAccessors(providers, config); + private final BundleAccessors baccForBundleAccessors = new BundleAccessors(objects, providers, config, attributesFactory, capabilityNotationParser); + private final PluginAccessors paccForPluginAccessors = new PluginAccessors(providers, config); + + @Inject + public LibrariesForLibsInPluginsBlock(DefaultVersionCatalog config, ProviderFactory providers, ObjectFactory objects, ImmutableAttributesFactory attributesFactory, CapabilityNotationParser capabilityNotationParser) { + super(config, providers, objects, attributesFactory, capabilityNotationParser); + } + + /** + * Group of libraries at androidx + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public AndroidxLibraryAccessors getAndroidx() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForAndroidxLibraryAccessors; + } + + /** + * Group of libraries at compose + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public ComposeLibraryAccessors getCompose() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForComposeLibraryAccessors; + } + + /** + * Group of libraries at datastore + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public DatastoreLibraryAccessors getDatastore() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForDatastoreLibraryAccessors; + } + + /** + * Group of libraries at hilt + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public HiltLibraryAccessors getHilt() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForHiltLibraryAccessors; + } + + /** + * Group of libraries at kotlinx + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public KotlinxLibraryAccessors getKotlinx() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForKotlinxLibraryAccessors; + } + + /** + * Group of libraries at lifecycle + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public LifecycleLibraryAccessors getLifecycle() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForLifecycleLibraryAccessors; + } + + /** + * Group of libraries at navigation + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public NavigationLibraryAccessors getNavigation() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForNavigationLibraryAccessors; + } + + /** + * Group of libraries at room + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public RoomLibraryAccessors getRoom() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForRoomLibraryAccessors; + } + + /** + * Group of versions at versions + */ + public VersionAccessors getVersions() { + return vaccForVersionAccessors; + } + + /** + * Group of bundles at bundles + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public BundleAccessors getBundles() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return baccForBundleAccessors; + } + + /** + * Group of plugins at plugins + */ + public PluginAccessors getPlugins() { + return paccForPluginAccessors; + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class AndroidxLibraryAccessors extends SubDependencyFactory { + private final AndroidxActivityLibraryAccessors laccForAndroidxActivityLibraryAccessors = new AndroidxActivityLibraryAccessors(owner); + private final AndroidxCoreLibraryAccessors laccForAndroidxCoreLibraryAccessors = new AndroidxCoreLibraryAccessors(owner); + + public AndroidxLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Group of libraries at androidx.activity + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public AndroidxActivityLibraryAccessors getActivity() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForAndroidxActivityLibraryAccessors; + } + + /** + * Group of libraries at androidx.core + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public AndroidxCoreLibraryAccessors getCore() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForAndroidxCoreLibraryAccessors; + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class AndroidxActivityLibraryAccessors extends SubDependencyFactory { + + public AndroidxActivityLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for compose with androidx.activity:activity-compose coordinates and + * with version reference activityCompose + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getCompose() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("androidx.activity.compose"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class AndroidxCoreLibraryAccessors extends SubDependencyFactory { + + public AndroidxCoreLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for ktx with androidx.core:core-ktx coordinates and + * with version reference coreKtx + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getKtx() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("androidx.core.ktx"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class ComposeLibraryAccessors extends SubDependencyFactory { + private final ComposeMaterialLibraryAccessors laccForComposeMaterialLibraryAccessors = new ComposeMaterialLibraryAccessors(owner); + private final ComposeUiLibraryAccessors laccForComposeUiLibraryAccessors = new ComposeUiLibraryAccessors(owner); + + public ComposeLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for bom with androidx.compose:compose-bom coordinates and + * with version reference composeBom + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getBom() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("compose.bom"); + } + + /** + * Dependency provider for material3 with androidx.compose.material3:material3 coordinates and + * with no version specified + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getMaterial3() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("compose.material3"); + } + + /** + * Group of libraries at compose.material + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public ComposeMaterialLibraryAccessors getMaterial() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForComposeMaterialLibraryAccessors; + } + + /** + * Group of libraries at compose.ui + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public ComposeUiLibraryAccessors getUi() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForComposeUiLibraryAccessors; + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class ComposeMaterialLibraryAccessors extends SubDependencyFactory { + private final ComposeMaterialIconsLibraryAccessors laccForComposeMaterialIconsLibraryAccessors = new ComposeMaterialIconsLibraryAccessors(owner); + + public ComposeMaterialLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Group of libraries at compose.material.icons + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public ComposeMaterialIconsLibraryAccessors getIcons() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForComposeMaterialIconsLibraryAccessors; + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class ComposeMaterialIconsLibraryAccessors extends SubDependencyFactory { + + public ComposeMaterialIconsLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for extended with androidx.compose.material:material-icons-extended coordinates and + * with no version specified + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getExtended() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("compose.material.icons.extended"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class ComposeUiLibraryAccessors extends SubDependencyFactory implements DependencyNotationSupplier { + private final ComposeUiToolingLibraryAccessors laccForComposeUiToolingLibraryAccessors = new ComposeUiToolingLibraryAccessors(owner); + + public ComposeUiLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for ui with androidx.compose.ui:ui coordinates and + * with no version specified + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider asProvider() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("compose.ui"); + } + + /** + * Dependency provider for graphics with androidx.compose.ui:ui-graphics coordinates and + * with no version specified + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getGraphics() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("compose.ui.graphics"); + } + + /** + * Group of libraries at compose.ui.tooling + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public ComposeUiToolingLibraryAccessors getTooling() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForComposeUiToolingLibraryAccessors; + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class ComposeUiToolingLibraryAccessors extends SubDependencyFactory implements DependencyNotationSupplier { + + public ComposeUiToolingLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for tooling with androidx.compose.ui:ui-tooling coordinates and + * with no version specified + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider asProvider() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("compose.ui.tooling"); + } + + /** + * Dependency provider for preview with androidx.compose.ui:ui-tooling-preview coordinates and + * with no version specified + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getPreview() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("compose.ui.tooling.preview"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class DatastoreLibraryAccessors extends SubDependencyFactory { + + public DatastoreLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for preferences with androidx.datastore:datastore-preferences coordinates and + * with version reference datastore + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getPreferences() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("datastore.preferences"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class HiltLibraryAccessors extends SubDependencyFactory { + private final HiltNavigationLibraryAccessors laccForHiltNavigationLibraryAccessors = new HiltNavigationLibraryAccessors(owner); + + public HiltLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for android with com.google.dagger:hilt-android coordinates and + * with version reference hilt + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getAndroid() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("hilt.android"); + } + + /** + * Dependency provider for compiler with com.google.dagger:hilt-android-compiler coordinates and + * with version reference hilt + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getCompiler() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("hilt.compiler"); + } + + /** + * Group of libraries at hilt.navigation + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public HiltNavigationLibraryAccessors getNavigation() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForHiltNavigationLibraryAccessors; + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class HiltNavigationLibraryAccessors extends SubDependencyFactory { + + public HiltNavigationLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for compose with androidx.hilt:hilt-navigation-compose coordinates and + * with version reference hiltNavigationCompose + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getCompose() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("hilt.navigation.compose"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class KotlinxLibraryAccessors extends SubDependencyFactory { + private final KotlinxCoroutinesLibraryAccessors laccForKotlinxCoroutinesLibraryAccessors = new KotlinxCoroutinesLibraryAccessors(owner); + private final KotlinxSerializationLibraryAccessors laccForKotlinxSerializationLibraryAccessors = new KotlinxSerializationLibraryAccessors(owner); + + public KotlinxLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Group of libraries at kotlinx.coroutines + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public KotlinxCoroutinesLibraryAccessors getCoroutines() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForKotlinxCoroutinesLibraryAccessors; + } + + /** + * Group of libraries at kotlinx.serialization + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public KotlinxSerializationLibraryAccessors getSerialization() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForKotlinxSerializationLibraryAccessors; + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class KotlinxCoroutinesLibraryAccessors extends SubDependencyFactory { + + public KotlinxCoroutinesLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for android with org.jetbrains.kotlinx:kotlinx-coroutines-android coordinates and + * with version reference coroutines + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getAndroid() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("kotlinx.coroutines.android"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class KotlinxSerializationLibraryAccessors extends SubDependencyFactory { + + public KotlinxSerializationLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for json with org.jetbrains.kotlinx:kotlinx-serialization-json coordinates and + * with version reference serialization + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getJson() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("kotlinx.serialization.json"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class LifecycleLibraryAccessors extends SubDependencyFactory { + private final LifecycleRuntimeLibraryAccessors laccForLifecycleRuntimeLibraryAccessors = new LifecycleRuntimeLibraryAccessors(owner); + private final LifecycleViewmodelLibraryAccessors laccForLifecycleViewmodelLibraryAccessors = new LifecycleViewmodelLibraryAccessors(owner); + + public LifecycleLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Group of libraries at lifecycle.runtime + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public LifecycleRuntimeLibraryAccessors getRuntime() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForLifecycleRuntimeLibraryAccessors; + } + + /** + * Group of libraries at lifecycle.viewmodel + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public LifecycleViewmodelLibraryAccessors getViewmodel() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return laccForLifecycleViewmodelLibraryAccessors; + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class LifecycleRuntimeLibraryAccessors extends SubDependencyFactory { + + public LifecycleRuntimeLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for compose with androidx.lifecycle:lifecycle-runtime-compose coordinates and + * with version reference lifecycle + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getCompose() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("lifecycle.runtime.compose"); + } + + /** + * Dependency provider for ktx with androidx.lifecycle:lifecycle-runtime-ktx coordinates and + * with version reference lifecycle + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getKtx() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("lifecycle.runtime.ktx"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class LifecycleViewmodelLibraryAccessors extends SubDependencyFactory { + + public LifecycleViewmodelLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for compose with androidx.lifecycle:lifecycle-viewmodel-compose coordinates and + * with version reference lifecycle + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getCompose() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("lifecycle.viewmodel.compose"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class NavigationLibraryAccessors extends SubDependencyFactory { + + public NavigationLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for compose with androidx.navigation:navigation-compose coordinates and + * with version reference navigationCompose + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getCompose() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("navigation.compose"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class RoomLibraryAccessors extends SubDependencyFactory { + + public RoomLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for compiler with androidx.room:room-compiler coordinates and + * with version reference room + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getCompiler() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("room.compiler"); + } + + /** + * Dependency provider for ktx with androidx.room:room-ktx coordinates and + * with version reference room + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getKtx() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("room.ktx"); + } + + /** + * Dependency provider for runtime with androidx.room:room-runtime coordinates and + * with version reference room + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getRuntime() { + org.gradle.internal.deprecation.DeprecationLogger.deprecateBehaviour("Accessing libraries or bundles from version catalogs in the plugins block.").withAdvice("Only use versions or plugins from catalogs in the plugins block.").willBeRemovedInGradle9().withUpgradeGuideSection(8, "kotlin_dsl_deprecated_catalogs_plugins_block").nagUser(); + return create("room.runtime"); + } + + } + + public static class VersionAccessors extends VersionFactory { + + public VersionAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); } + + /** + * Version alias activityCompose with value 1.9.0 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getActivityCompose() { return getVersion("activityCompose"); } + + /** + * Version alias agp with value 8.4.1 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getAgp() { return getVersion("agp"); } + + /** + * Version alias composeBom with value 2024.06.00 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getComposeBom() { return getVersion("composeBom"); } + + /** + * Version alias coreKtx with value 1.13.1 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getCoreKtx() { return getVersion("coreKtx"); } + + /** + * Version alias coroutines with value 1.8.1 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getCoroutines() { return getVersion("coroutines"); } + + /** + * Version alias datastore with value 1.1.1 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getDatastore() { return getVersion("datastore"); } + + /** + * Version alias hilt with value 2.51.1 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getHilt() { return getVersion("hilt"); } + + /** + * Version alias hiltNavigationCompose with value 1.2.0 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getHiltNavigationCompose() { return getVersion("hiltNavigationCompose"); } + + /** + * Version alias kotlin with value 2.0.0 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getKotlin() { return getVersion("kotlin"); } + + /** + * Version alias ksp with value 2.0.0-1.0.21 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getKsp() { return getVersion("ksp"); } + + /** + * Version alias lifecycle with value 2.8.2 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getLifecycle() { return getVersion("lifecycle"); } + + /** + * Version alias navigationCompose with value 2.7.7 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getNavigationCompose() { return getVersion("navigationCompose"); } + + /** + * Version alias room with value 2.6.1 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getRoom() { return getVersion("room"); } + + /** + * Version alias serialization with value 1.7.1 + *

+ * If the version is a rich version and cannot be represented as a + * single version string, an empty string is returned. + *

+ * This version was declared in catalog libs.versions.toml + */ + public Provider getSerialization() { return getVersion("serialization"); } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class BundleAccessors extends BundleFactory { + + public BundleAccessors(ObjectFactory objects, ProviderFactory providers, DefaultVersionCatalog config, ImmutableAttributesFactory attributesFactory, CapabilityNotationParser capabilityNotationParser) { super(objects, providers, config, attributesFactory, capabilityNotationParser); } + + } + + public static class PluginAccessors extends PluginFactory { + private final AndroidPluginAccessors paccForAndroidPluginAccessors = new AndroidPluginAccessors(providers, config); + private final KotlinPluginAccessors paccForKotlinPluginAccessors = new KotlinPluginAccessors(providers, config); + + public PluginAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); } + + /** + * Plugin provider for hilt with plugin id com.google.dagger.hilt.android and + * with version reference hilt + *

+ * This plugin was declared in catalog libs.versions.toml + */ + public Provider getHilt() { return createPlugin("hilt"); } + + /** + * Plugin provider for ksp with plugin id com.google.devtools.ksp and + * with version reference ksp + *

+ * This plugin was declared in catalog libs.versions.toml + */ + public Provider getKsp() { return createPlugin("ksp"); } + + /** + * Group of plugins at plugins.android + */ + public AndroidPluginAccessors getAndroid() { + return paccForAndroidPluginAccessors; + } + + /** + * Group of plugins at plugins.kotlin + */ + public KotlinPluginAccessors getKotlin() { + return paccForKotlinPluginAccessors; + } + + } + + public static class AndroidPluginAccessors extends PluginFactory { + + public AndroidPluginAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); } + + /** + * Plugin provider for android.application with plugin id com.android.application and + * with version reference agp + *

+ * This plugin was declared in catalog libs.versions.toml + */ + public Provider getApplication() { return createPlugin("android.application"); } + + } + + public static class KotlinPluginAccessors extends PluginFactory { + + public KotlinPluginAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); } + + /** + * Plugin provider for kotlin.android with plugin id org.jetbrains.kotlin.android and + * with version reference kotlin + *

+ * This plugin was declared in catalog libs.versions.toml + */ + public Provider getAndroid() { return createPlugin("kotlin.android"); } + + /** + * Plugin provider for kotlin.compose with plugin id org.jetbrains.kotlin.plugin.compose and + * with version reference kotlin + *

+ * This plugin was declared in catalog libs.versions.toml + */ + public Provider getCompose() { return createPlugin("kotlin.compose"); } + + /** + * Plugin provider for kotlin.serialization with plugin id org.jetbrains.kotlin.plugin.serialization and + * with version reference kotlin + *

+ * This plugin was declared in catalog libs.versions.toml + */ + public Provider getSerialization() { return createPlugin("kotlin.serialization"); } + + } + +} diff --git a/.gradle/8.7/executionHistory/executionHistory.lock b/.gradle/8.7/executionHistory/executionHistory.lock new file mode 100644 index 0000000000000000000000000000000000000000..f985283881db03221f05edcdca0d69ff42d5a2b7 GIT binary patch literal 17 UcmZSnen;TwgN6AI86dy`07YX3y#N3J literal 0 HcmV?d00001 diff --git a/.gradle/8.7/fileHashes/fileHashes.bin b/.gradle/8.7/fileHashes/fileHashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..1cfd45ede383530f9857d602c06d433ba6dc75fc GIT binary patch literal 147033 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 literal 0 HcmV?d00001 diff --git a/.gradle/8.7/fileHashes/fileHashes.lock b/.gradle/8.7/fileHashes/fileHashes.lock new file mode 100644 index 0000000000000000000000000000000000000000..d5437c7a482c908d5f2b4bd0de654be096085016 GIT binary patch literal 17 VcmZS1{_?7O!~L|M3}C=98vsaH25A5Q literal 0 HcmV?d00001 diff --git a/.gradle/8.7/fileHashes/resourceHashesCache.bin b/.gradle/8.7/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000000000000000000000000000000000000..efb62584627d13f6fbd9ede5e61945c060e1748e GIT binary patch literal 63311 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%0D^&>T}VcP;9014|&|`9K*+GthmHg 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 literal 0 HcmV?d00001 diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000000000000000000000000000000000000..3f9d964bf554a1ad7125eb6cfe952b3b8cde677c GIT binary patch literal 17 VcmZSf`?!lup?{qO0~jz`0{|^U1GE4D literal 0 HcmV?d00001 diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000..0ae8178 --- /dev/null +++ b/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Fri May 22 16:56:02 CDT 2026 +gradle.version=8.7 diff --git a/.gradle/config.properties b/.gradle/config.properties new file mode 100644 index 0000000..16d1193 --- /dev/null +++ b/.gradle/config.properties @@ -0,0 +1,2 @@ +#Fri May 22 16:55:12 CDT 2026 +java.home=C\:\\Program Files\\Android\\Android Studio\\jbr diff --git a/.gradle/file-system.probe b/.gradle/file-system.probe new file mode 100644 index 0000000000000000000000000000000000000000..1333b3d68949d2104b127f9fb157f0e6404aef11 GIT binary patch literal 8 PcmZQzV4N3tsQy0y2&)4z literal 0 HcmV?d00001 diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..97f0a8e --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..74dd639 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..d0752fa --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,76 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.hilt) + alias(libs.plugins.ksp) +} + +android { + namespace = "com.hsdiary" + compileSdk = 34 + + defaultConfig { + applicationId = "com.hsdiary" + minSdk = 26 + targetSdk = 34 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary = true + } + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } + buildFeatures { + compose = true + } + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + } + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.compose.bom)) + implementation(libs.compose.ui) + implementation(libs.compose.ui.graphics) + implementation(libs.compose.ui.tooling.preview) + implementation(libs.compose.material3) + implementation(libs.compose.material.icons.extended) + implementation(libs.lifecycle.runtime.ktx) + implementation(libs.lifecycle.viewmodel.compose) + implementation(libs.lifecycle.runtime.compose) + implementation(libs.navigation.compose) + implementation(libs.hilt.android) + ksp(libs.hilt.compiler) + implementation(libs.hilt.navigation.compose) + implementation(libs.room.runtime) + implementation(libs.room.ktx) + ksp(libs.room.compiler) + implementation(libs.datastore.preferences) + implementation(libs.kotlinx.coroutines.android) + implementation(libs.kotlinx.serialization.json) + debugImplementation(libs.compose.ui.tooling) +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..215a79c --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,2 @@ +-keep class com.hsdiary.** { *; } +-keepattributes *Annotation* diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..2ba417e --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + diff --git a/app/src/main/java/com/hsdiary/HSDiaryApplication.kt b/app/src/main/java/com/hsdiary/HSDiaryApplication.kt new file mode 100644 index 0000000..01c311f --- /dev/null +++ b/app/src/main/java/com/hsdiary/HSDiaryApplication.kt @@ -0,0 +1,7 @@ +package com.hsdiary + +import android.app.Application +import dagger.hilt.android.HiltAndroidApp + +@HiltAndroidApp +class HSDiaryApplication : Application() diff --git a/app/src/main/java/com/hsdiary/MainActivity.kt b/app/src/main/java/com/hsdiary/MainActivity.kt new file mode 100644 index 0000000..9c19d4c --- /dev/null +++ b/app/src/main/java/com/hsdiary/MainActivity.kt @@ -0,0 +1,22 @@ +package com.hsdiary + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import com.hsdiary.ui.navigation.AppNavigation +import com.hsdiary.ui.theme.HSDiaryTheme +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContent { + HSDiaryTheme { + AppNavigation() + } + } + } +} diff --git a/app/src/main/java/com/hsdiary/data/db/AppDatabase.kt b/app/src/main/java/com/hsdiary/data/db/AppDatabase.kt new file mode 100644 index 0000000..fc5f287 --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/db/AppDatabase.kt @@ -0,0 +1,133 @@ +package com.hsdiary.data.db + +import androidx.room.Database +import androidx.room.RoomDatabase +import androidx.sqlite.db.SupportSQLiteDatabase +import com.hsdiary.data.db.dao.* +import com.hsdiary.data.db.entity.* + +@Database( + entities = [ + ProfileEntity::class, + DayLogEntity::class, + ConditionEntryEntity::class, + CycleRecordEntity::class, + IntimacyLogEntity::class, + ConditionDefinitionEntity::class + ], + version = 1, + exportSchema = false +) +abstract class AppDatabase : RoomDatabase() { + abstract fun profileDao(): ProfileDao + abstract fun dayLogDao(): DayLogDao + abstract fun conditionDao(): ConditionDao + abstract fun cycleRecordDao(): CycleRecordDao + abstract fun intimacyLogDao(): IntimacyLogDao + abstract fun conditionDefinitionDao(): ConditionDefinitionDao + + companion object { + val seedCallback = object : Callback() { + override fun onCreate(db: SupportSQLiteDatabase) { + super.onCreate(db) + seedConditionDefinitions(db) + } + + private fun seedConditionDefinitions(db: SupportSQLiteDatabase) { + data class Seed(val key: String, val name: String, val cat: String, val vis: String, val order: Int) + + val seeds = listOf( + // Head & Neurological + Seed("HEADACHE", "Headache", "HEAD_NEUROLOGICAL", "ALL", 0), + Seed("MIGRAINE", "Migraine", "HEAD_NEUROLOGICAL", "ALL", 1), + Seed("BRAIN_FOG", "Brain fog", "HEAD_NEUROLOGICAL", "ALL", 2), + Seed("DIZZINESS", "Dizziness", "HEAD_NEUROLOGICAL", "ALL", 3), + Seed("FAINTING", "Fainting / near-fainting", "HEAD_NEUROLOGICAL", "ALL", 4), + Seed("TINNITUS", "Tinnitus", "HEAD_NEUROLOGICAL", "ALL", 5), + Seed("VISION_DISTURBANCE", "Vision disturbance", "HEAD_NEUROLOGICAL", "ALL", 6), + Seed("NUMBNESS_TINGLING", "Numbness / tingling", "HEAD_NEUROLOGICAL", "ALL", 7), + // Digestive + Seed("NAUSEA", "Nausea", "DIGESTIVE", "ALL", 0), + Seed("VOMITING", "Vomiting", "DIGESTIVE", "ALL", 1), + Seed("BLOATING", "Bloating", "DIGESTIVE", "ALL", 2), + Seed("CONSTIPATION", "Constipation", "DIGESTIVE", "ALL", 3), + Seed("DIARRHEA", "Diarrhea", "DIGESTIVE", "ALL", 4), + Seed("ACID_REFLUX", "Acid reflux / heartburn", "DIGESTIVE", "ALL", 5), + Seed("APPETITE_LOSS", "Appetite loss", "DIGESTIVE", "ALL", 6), + Seed("APPETITE_INCREASE", "Appetite increase", "DIGESTIVE", "ALL", 7), + Seed("ABDOMINAL_CRAMPING", "Abdominal cramping", "DIGESTIVE", "ALL", 8), + Seed("GAS", "Gas", "DIGESTIVE", "ALL", 9), + // Musculoskeletal + Seed("BACK_PAIN", "Back pain", "MUSCULOSKELETAL", "ALL", 0), + Seed("NECK_PAIN", "Neck pain", "MUSCULOSKELETAL", "ALL", 1), + Seed("JOINT_PAIN", "Joint pain", "MUSCULOSKELETAL", "ALL", 2), + Seed("MUSCLE_ACHES", "Muscle aches", "MUSCULOSKELETAL", "ALL", 3), + Seed("MUSCLE_CRAMPS", "Muscle cramps", "MUSCULOSKELETAL", "ALL", 4), + Seed("STIFFNESS", "Stiffness", "MUSCULOSKELETAL", "ALL", 5), + Seed("SWOLLEN_JOINTS", "Swelling in joints", "MUSCULOSKELETAL", "ALL", 6), + // Respiratory + Seed("SHORTNESS_OF_BREATH", "Shortness of breath", "RESPIRATORY", "ALL", 0), + Seed("CHEST_TIGHTNESS", "Chest tightness", "RESPIRATORY", "ALL", 1), + Seed("COUGH", "Cough", "RESPIRATORY", "ALL", 2), + Seed("CONGESTION", "Congestion", "RESPIRATORY", "ALL", 3), + Seed("SORE_THROAT", "Sore throat", "RESPIRATORY", "ALL", 4), + Seed("WHEEZING", "Wheezing", "RESPIRATORY", "ALL", 5), + // Cardiovascular + Seed("HEART_PALPITATIONS", "Heart palpitations", "CARDIOVASCULAR", "ALL", 0), + Seed("CHEST_PAIN", "Chest pain", "CARDIOVASCULAR", "ALL", 1), + Seed("RAPID_HEARTBEAT", "Rapid heartbeat", "CARDIOVASCULAR", "ALL", 2), + Seed("LOW_BP_SYMPTOMS", "Low blood pressure symptoms", "CARDIOVASCULAR", "ALL", 3), + Seed("SWOLLEN_ANKLES", "Swollen ankles / feet", "CARDIOVASCULAR", "ALL", 4), + // Energy & Sleep + Seed("FATIGUE", "Fatigue", "ENERGY_SLEEP", "ALL", 0), + Seed("EXHAUSTION", "Exhaustion", "ENERGY_SLEEP", "ALL", 1), + Seed("INSOMNIA", "Insomnia", "ENERGY_SLEEP", "ALL", 2), + Seed("HYPERSOMNIA", "Hypersomnia (sleeping too much)", "ENERGY_SLEEP", "ALL", 3), + Seed("RESTLESS_SLEEP", "Restless sleep", "ENERGY_SLEEP", "ALL", 4), + Seed("NIGHT_SWEATS", "Night sweats", "ENERGY_SLEEP", "ALL", 5), + // Mood & Mental + Seed("ANXIOUS", "Anxious", "MOOD_MENTAL", "ALL", 0), + Seed("IRRITABLE", "Irritable", "MOOD_MENTAL", "ALL", 1), + Seed("DEPRESSED", "Depressed", "MOOD_MENTAL", "ALL", 2), + Seed("MOOD_SWINGS", "Mood swings", "MOOD_MENTAL", "ALL", 3), + Seed("OVERWHELMED", "Overwhelmed", "MOOD_MENTAL", "ALL", 4), + Seed("CALM", "Calm", "MOOD_MENTAL", "ALL", 5), + Seed("HAPPY", "Happy", "MOOD_MENTAL", "ALL", 6), + Seed("PANIC_ATTACK", "Panic attack", "MOOD_MENTAL", "ALL", 7), + Seed("LOW_MOTIVATION", "Low motivation", "MOOD_MENTAL", "ALL", 8), + // Skin + Seed("RASH", "Rash", "SKIN", "ALL", 0), + Seed("HIVES", "Hives", "SKIN", "ALL", 1), + Seed("ACNE", "Acne breakout", "SKIN", "ALL", 2), + Seed("DRY_SKIN", "Dry skin", "SKIN", "ALL", 3), + Seed("EXCESSIVE_SWEATING", "Excessive sweating", "SKIN", "ALL", 4), + Seed("ITCHING", "Itching", "SKIN", "ALL", 5), + Seed("BRUISING", "Bruising easily", "SKIN", "ALL", 6), + // Female-Specific + Seed("CRAMPS", "Cramps", "FEMALE_SPECIFIC", "FEMALE_ONLY", 0), + Seed("BREAST_TENDERNESS", "Breast tenderness", "FEMALE_SPECIFIC", "FEMALE_ONLY", 1), + Seed("SPOTTING", "Spotting", "FEMALE_SPECIFIC", "FEMALE_ONLY", 2), + Seed("DISCHARGE_NORMAL", "Discharge โ€” normal", "FEMALE_SPECIFIC", "FEMALE_ONLY", 3), + Seed("DISCHARGE_UNUSUAL", "Discharge โ€” unusual", "FEMALE_SPECIFIC", "FEMALE_ONLY", 4), + Seed("HOT_FLASHES", "Hot flashes", "FEMALE_SPECIFIC", "FEMALE_ONLY", 5), + Seed("PMS", "PMS symptoms", "FEMALE_SPECIFIC", "FEMALE_ONLY", 6), + Seed("OVULATION_PAIN", "Ovulation pain (Mittelschmerz)", "FEMALE_SPECIFIC", "FEMALE_ONLY", 7), + // General + Seed("FEVER", "Fever", "GENERAL", "ALL", 0), + Seed("CHILLS", "Chills", "GENERAL", "ALL", 1), + Seed("DEHYDRATION", "Dehydration", "GENERAL", "ALL", 2), + Seed("ALLERGIC_REACTION", "Allergic reaction", "GENERAL", "ALL", 3), + Seed("COLD_FLU", "Cold / flu symptoms", "GENERAL", "ALL", 4), + Seed("SWOLLEN_LYMPH", "Swollen lymph nodes", "GENERAL", "ALL", 5) + ) + seeds.forEach { s -> + val name = s.name.replace("'", "''") + db.execSQL( + "INSERT INTO condition_definitions (condition_key, display_name, category, profile_visibility, sort_order) " + + "VALUES ('${s.key}', '$name', '${s.cat}', '${s.vis}', ${s.order})" + ) + } + } + } + } +} diff --git a/app/src/main/java/com/hsdiary/data/db/dao/ConditionDao.kt b/app/src/main/java/com/hsdiary/data/db/dao/ConditionDao.kt new file mode 100644 index 0000000..053ea9c --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/db/dao/ConditionDao.kt @@ -0,0 +1,33 @@ +package com.hsdiary.data.db.dao + +import androidx.room.* +import com.hsdiary.data.db.entity.ConditionEntryEntity +import kotlinx.coroutines.flow.Flow + +@Dao +interface ConditionDao { + @Query("SELECT * FROM conditions WHERE day_log_id = :dayLogId") + fun getConditionsForDay(dayLogId: Long): Flow> + + @Query("SELECT * FROM conditions WHERE day_log_id = :dayLogId") + suspend fun getConditionsForDayOnce(dayLogId: Long): List + + @Query(""" + SELECT c.* FROM conditions c + JOIN day_logs dl ON c.day_log_id = dl.id + WHERE dl.profile_id = :profileId AND dl.date >= :startDate AND dl.date <= :endDate + """) + suspend fun getConditionsInRange(profileId: Long, startDate: String, endDate: String): List + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertCondition(condition: ConditionEntryEntity): Long + + @Delete + suspend fun deleteCondition(condition: ConditionEntryEntity) + + @Query("DELETE FROM conditions WHERE day_log_id = :dayLogId AND condition_key = :conditionKey") + suspend fun deleteConditionByKey(dayLogId: Long, conditionKey: String) + + @Query("DELETE FROM conditions WHERE day_log_id = :dayLogId") + suspend fun deleteAllForDayLog(dayLogId: Long) +} diff --git a/app/src/main/java/com/hsdiary/data/db/dao/ConditionDefinitionDao.kt b/app/src/main/java/com/hsdiary/data/db/dao/ConditionDefinitionDao.kt new file mode 100644 index 0000000..d4fd4f6 --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/db/dao/ConditionDefinitionDao.kt @@ -0,0 +1,23 @@ +package com.hsdiary.data.db.dao + +import androidx.room.* +import com.hsdiary.data.db.entity.ConditionDefinitionEntity +import kotlinx.coroutines.flow.Flow + +@Dao +interface ConditionDefinitionDao { + @Query("SELECT * FROM condition_definitions ORDER BY category, sort_order") + fun getAllDefinitions(): Flow> + + @Query("SELECT * FROM condition_definitions ORDER BY category, sort_order") + suspend fun getAllDefinitionsOnce(): List + + @Query("SELECT * FROM condition_definitions WHERE profile_visibility = 'ALL' OR profile_visibility = :visibility ORDER BY category, sort_order") + suspend fun getDefinitionsForProfile(visibility: String): List + + @Insert(onConflict = OnConflictStrategy.IGNORE) + suspend fun insertAll(definitions: List) + + @Query("SELECT COUNT(*) FROM condition_definitions") + suspend fun getCount(): Int +} diff --git a/app/src/main/java/com/hsdiary/data/db/dao/CycleRecordDao.kt b/app/src/main/java/com/hsdiary/data/db/dao/CycleRecordDao.kt new file mode 100644 index 0000000..c6f2ecf --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/db/dao/CycleRecordDao.kt @@ -0,0 +1,32 @@ +package com.hsdiary.data.db.dao + +import androidx.room.* +import com.hsdiary.data.db.entity.CycleRecordEntity +import kotlinx.coroutines.flow.Flow + +@Dao +interface CycleRecordDao { + @Query("SELECT * FROM cycle_records WHERE profile_id = :profileId ORDER BY cycle_start ASC") + fun getCycleRecords(profileId: Long): Flow> + + @Query("SELECT * FROM cycle_records WHERE profile_id = :profileId ORDER BY cycle_start ASC") + suspend fun getCycleRecordsOnce(profileId: Long): List + + @Query("SELECT * FROM cycle_records WHERE profile_id = :profileId ORDER BY cycle_start DESC LIMIT 1") + suspend fun getLatestCycleRecord(profileId: Long): CycleRecordEntity? + + @Query("SELECT * FROM cycle_records WHERE profile_id = :profileId AND cycle_end IS NULL ORDER BY cycle_start DESC LIMIT 1") + suspend fun getCurrentCycleRecord(profileId: Long): CycleRecordEntity? + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertCycleRecord(record: CycleRecordEntity): Long + + @Update + suspend fun updateCycleRecord(record: CycleRecordEntity) + + @Delete + suspend fun deleteCycleRecord(record: CycleRecordEntity) + + @Query("DELETE FROM cycle_records WHERE profile_id = :profileId") + suspend fun deleteAllForProfile(profileId: Long) +} diff --git a/app/src/main/java/com/hsdiary/data/db/dao/DayLogDao.kt b/app/src/main/java/com/hsdiary/data/db/dao/DayLogDao.kt new file mode 100644 index 0000000..b53a0dc --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/db/dao/DayLogDao.kt @@ -0,0 +1,32 @@ +package com.hsdiary.data.db.dao + +import androidx.room.* +import com.hsdiary.data.db.entity.DayLogEntity +import kotlinx.coroutines.flow.Flow + +@Dao +interface DayLogDao { + @Query("SELECT * FROM day_logs WHERE profile_id = :profileId AND date = :date") + suspend fun getDayLog(profileId: Long, date: String): DayLogEntity? + + @Query("SELECT * FROM day_logs WHERE profile_id = :profileId AND date = :date") + fun getDayLogFlow(profileId: Long, date: String): Flow + + @Query("SELECT * FROM day_logs WHERE profile_id = :profileId AND date >= :startDate AND date <= :endDate ORDER BY date ASC") + fun getDayLogsInRange(profileId: Long, startDate: String, endDate: String): Flow> + + @Query("SELECT * FROM day_logs WHERE profile_id = :profileId AND date >= :startDate AND date <= :endDate ORDER BY date ASC") + suspend fun getDayLogsInRangeOnce(profileId: Long, startDate: String, endDate: String): List + + @Query("SELECT * FROM day_logs WHERE profile_id = :profileId AND period_active = 1 ORDER BY date ASC") + suspend fun getPeriodDays(profileId: Long): List + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertDayLog(dayLog: DayLogEntity): Long + + @Update + suspend fun updateDayLog(dayLog: DayLogEntity) + + @Query("DELETE FROM day_logs WHERE profile_id = :profileId") + suspend fun deleteAllForProfile(profileId: Long) +} diff --git a/app/src/main/java/com/hsdiary/data/db/dao/IntimacyLogDao.kt b/app/src/main/java/com/hsdiary/data/db/dao/IntimacyLogDao.kt new file mode 100644 index 0000000..f66723e --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/db/dao/IntimacyLogDao.kt @@ -0,0 +1,32 @@ +package com.hsdiary.data.db.dao + +import androidx.room.* +import com.hsdiary.data.db.entity.IntimacyLogEntity +import kotlinx.coroutines.flow.Flow + +@Dao +interface IntimacyLogDao { + @Query("SELECT * FROM intimacy_logs WHERE date = :date AND owner_profile_id = :profileId ORDER BY rowid ASC") + fun getLogsForDay(date: String, profileId: Long): Flow> + + @Query("SELECT * FROM intimacy_logs WHERE date = :date AND owner_profile_id = :profileId ORDER BY rowid ASC") + suspend fun getLogsForDayOnce(date: String, profileId: Long): List + + @Query("SELECT DISTINCT date FROM intimacy_logs WHERE owner_profile_id = :profileId AND date >= :startDate AND date <= :endDate") + suspend fun getDatesWithLogs(profileId: Long, startDate: String, endDate: String): List + + @Query("SELECT * FROM intimacy_logs WHERE date >= :startDate AND date <= :endDate AND owner_profile_id = :profileId ORDER BY date ASC") + suspend fun getLogsInRange(profileId: Long, startDate: String, endDate: String): List + + @Insert + suspend fun insertLog(log: IntimacyLogEntity): Long + + @Update + suspend fun updateLog(log: IntimacyLogEntity) + + @Delete + suspend fun deleteLog(log: IntimacyLogEntity) + + @Query("DELETE FROM intimacy_logs WHERE owner_profile_id = :profileId") + suspend fun deleteAllForProfile(profileId: Long) +} diff --git a/app/src/main/java/com/hsdiary/data/db/dao/ProfileDao.kt b/app/src/main/java/com/hsdiary/data/db/dao/ProfileDao.kt new file mode 100644 index 0000000..68528da --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/db/dao/ProfileDao.kt @@ -0,0 +1,29 @@ +package com.hsdiary.data.db.dao + +import androidx.room.* +import com.hsdiary.data.db.entity.ProfileEntity +import kotlinx.coroutines.flow.Flow + +@Dao +interface ProfileDao { + @Query("SELECT * FROM profiles ORDER BY created_at ASC") + fun getAllProfiles(): Flow> + + @Query("SELECT * FROM profiles ORDER BY created_at ASC") + suspend fun getAllProfilesOnce(): List + + @Query("SELECT * FROM profiles WHERE id = :id") + suspend fun getProfileById(id: Long): ProfileEntity? + + @Query("SELECT COUNT(*) FROM profiles") + suspend fun getProfileCount(): Int + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertProfile(profile: ProfileEntity): Long + + @Update + suspend fun updateProfile(profile: ProfileEntity) + + @Delete + suspend fun deleteProfile(profile: ProfileEntity) +} diff --git a/app/src/main/java/com/hsdiary/data/db/entity/ConditionDefinitionEntity.kt b/app/src/main/java/com/hsdiary/data/db/entity/ConditionDefinitionEntity.kt new file mode 100644 index 0000000..94ea12d --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/db/entity/ConditionDefinitionEntity.kt @@ -0,0 +1,15 @@ +package com.hsdiary.data.db.entity + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "condition_definitions") +data class ConditionDefinitionEntity( + @PrimaryKey(autoGenerate = true) val id: Long = 0, + @ColumnInfo(name = "condition_key") val conditionKey: String, + @ColumnInfo(name = "display_name") val displayName: String, + val category: String, + @ColumnInfo(name = "profile_visibility") val profileVisibility: String, + @ColumnInfo(name = "sort_order") val sortOrder: Int +) diff --git a/app/src/main/java/com/hsdiary/data/db/entity/ConditionEntryEntity.kt b/app/src/main/java/com/hsdiary/data/db/entity/ConditionEntryEntity.kt new file mode 100644 index 0000000..63aeece --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/db/entity/ConditionEntryEntity.kt @@ -0,0 +1,24 @@ +package com.hsdiary.data.db.entity + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.Index +import androidx.room.PrimaryKey + +@Entity( + tableName = "conditions", + foreignKeys = [ForeignKey( + entity = DayLogEntity::class, + parentColumns = ["id"], + childColumns = ["day_log_id"], + onDelete = ForeignKey.CASCADE + )], + indices = [Index("day_log_id")] +) +data class ConditionEntryEntity( + @PrimaryKey(autoGenerate = true) val id: Long = 0, + @ColumnInfo(name = "day_log_id") val dayLogId: Long, + @ColumnInfo(name = "condition_key") val conditionKey: String, + val rating: Int = 3 +) diff --git a/app/src/main/java/com/hsdiary/data/db/entity/CycleRecordEntity.kt b/app/src/main/java/com/hsdiary/data/db/entity/CycleRecordEntity.kt new file mode 100644 index 0000000..1e0c293 --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/db/entity/CycleRecordEntity.kt @@ -0,0 +1,27 @@ +package com.hsdiary.data.db.entity + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.Index +import androidx.room.PrimaryKey + +@Entity( + tableName = "cycle_records", + foreignKeys = [ForeignKey( + entity = ProfileEntity::class, + parentColumns = ["id"], + childColumns = ["profile_id"], + onDelete = ForeignKey.CASCADE + )], + indices = [Index("profile_id")] +) +data class CycleRecordEntity( + @PrimaryKey(autoGenerate = true) val id: Long = 0, + @ColumnInfo(name = "profile_id") val profileId: Long, + @ColumnInfo(name = "cycle_start") val cycleStart: String, + @ColumnInfo(name = "cycle_end") val cycleEnd: String? = null, + @ColumnInfo(name = "cycle_length") val cycleLength: Int? = null, + @ColumnInfo(name = "predicted_start") val predictedStart: String? = null, + @ColumnInfo(name = "delta_days") val deltaDays: Int? = null +) diff --git a/app/src/main/java/com/hsdiary/data/db/entity/DayLogEntity.kt b/app/src/main/java/com/hsdiary/data/db/entity/DayLogEntity.kt new file mode 100644 index 0000000..2ed2ede --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/db/entity/DayLogEntity.kt @@ -0,0 +1,25 @@ +package com.hsdiary.data.db.entity + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.Index +import androidx.room.PrimaryKey + +@Entity( + tableName = "day_logs", + foreignKeys = [ForeignKey( + entity = ProfileEntity::class, + parentColumns = ["id"], + childColumns = ["profile_id"], + onDelete = ForeignKey.CASCADE + )], + indices = [Index("profile_id"), Index(value = ["profile_id", "date"], unique = true)] +) +data class DayLogEntity( + @PrimaryKey(autoGenerate = true) val id: Long = 0, + @ColumnInfo(name = "profile_id") val profileId: Long, + val date: String, + @ColumnInfo(name = "period_active") val periodActive: Boolean = false, + val notes: String? = null +) diff --git a/app/src/main/java/com/hsdiary/data/db/entity/IntimacyLogEntity.kt b/app/src/main/java/com/hsdiary/data/db/entity/IntimacyLogEntity.kt new file mode 100644 index 0000000..cc05fc3 --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/db/entity/IntimacyLogEntity.kt @@ -0,0 +1,28 @@ +package com.hsdiary.data.db.entity + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.Index +import androidx.room.PrimaryKey + +@Entity( + tableName = "intimacy_logs", + foreignKeys = [ForeignKey( + entity = ProfileEntity::class, + parentColumns = ["id"], + childColumns = ["owner_profile_id"], + onDelete = ForeignKey.CASCADE + )], + indices = [Index("owner_profile_id")] +) +data class IntimacyLogEntity( + @PrimaryKey(autoGenerate = true) val id: Long = 0, + val date: String, + @ColumnInfo(name = "owner_profile_id") val ownerProfileId: Long, + @ColumnInfo(name = "participant_type") val participantType: String, + @ColumnInfo(name = "participant_name") val participantName: String? = null, + @ColumnInfo(name = "time_of_day") val timeOfDay: String? = null, + val protected: Boolean = true, + val shared: Boolean = true +) diff --git a/app/src/main/java/com/hsdiary/data/db/entity/ProfileEntity.kt b/app/src/main/java/com/hsdiary/data/db/entity/ProfileEntity.kt new file mode 100644 index 0000000..9958683 --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/db/entity/ProfileEntity.kt @@ -0,0 +1,17 @@ +package com.hsdiary.data.db.entity + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "profiles") +data class ProfileEntity( + @PrimaryKey(autoGenerate = true) + val id: Long = 0, + val name: String, + @ColumnInfo(name = "avatar_color") val avatarColor: String, + @ColumnInfo(name = "profile_type") val profileType: String, + @ColumnInfo(name = "created_at") val createdAt: Long = System.currentTimeMillis(), + @ColumnInfo(name = "cycle_length_default") val cycleLengthDefault: Int = 28, + @ColumnInfo(name = "reproductive_status") val reproductiveStatus: String = "{}" +) diff --git a/app/src/main/java/com/hsdiary/data/model/ConditionCategory.kt b/app/src/main/java/com/hsdiary/data/model/ConditionCategory.kt new file mode 100644 index 0000000..1320442 --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/model/ConditionCategory.kt @@ -0,0 +1,14 @@ +package com.hsdiary.data.model + +enum class ConditionCategory(val displayName: String) { + HEAD_NEUROLOGICAL("Head & Neurological"), + DIGESTIVE("Digestive"), + MUSCULOSKELETAL("Musculoskeletal"), + RESPIRATORY("Respiratory"), + CARDIOVASCULAR("Cardiovascular"), + ENERGY_SLEEP("Energy & Sleep"), + MOOD_MENTAL("Mood & Mental"), + SKIN("Skin"), + FEMALE_SPECIFIC("Female-Specific"), + GENERAL("General") +} diff --git a/app/src/main/java/com/hsdiary/data/model/CyclePhase.kt b/app/src/main/java/com/hsdiary/data/model/CyclePhase.kt new file mode 100644 index 0000000..362b619 --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/model/CyclePhase.kt @@ -0,0 +1,13 @@ +package com.hsdiary.data.model + +enum class CyclePhase { + MENSTRUATION_CONFIRMED, + MENSTRUATION_PREDICTED, + FERTILE_WINDOW, + FERTILE_WINDOW_PREDICTED, + OVULATION, + OVULATION_PREDICTED, + LUTEAL, + FOLLICULAR, + NO_DATA +} diff --git a/app/src/main/java/com/hsdiary/data/model/ProfileType.kt b/app/src/main/java/com/hsdiary/data/model/ProfileType.kt new file mode 100644 index 0000000..1910a7e --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/model/ProfileType.kt @@ -0,0 +1,3 @@ +package com.hsdiary.data.model + +enum class ProfileType { FEMALE, MALE } diff --git a/app/src/main/java/com/hsdiary/data/model/ReproductiveStatus.kt b/app/src/main/java/com/hsdiary/data/model/ReproductiveStatus.kt new file mode 100644 index 0000000..5cb198e --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/model/ReproductiveStatus.kt @@ -0,0 +1,30 @@ +package com.hsdiary.data.model + +import kotlinx.serialization.Serializable + +enum class FemaleReproductiveStatus(val label: String) { + NORMAL("Normal / no known factors"), + HORMONAL_BC("Hormonal birth control"), + IUD_HORMONAL("IUD โ€” hormonal"), + IUD_COPPER("IUD โ€” copper"), + TUBAL_LIGATION("Tubal ligation"), + TRYING_TO_CONCEIVE("Trying to conceive"), + PREGNANT("Pregnant"), + POSTPARTUM("Postpartum"), + IRREGULAR("Irregular / perimenopause"), + OTHER("Other / prefer not to say") +} + +enum class MaleReproductiveStatus(val label: String) { + NORMAL("Normal / no known factors"), + VASECTOMY_CONFIRMED("Vasectomy โ€” confirmed"), + VASECTOMY_PENDING("Vasectomy โ€” awaiting confirmation"), + OTHER("Other / prefer not to say") +} + +@Serializable +data class ReproductiveStatusData( + val femaleStatus: String = FemaleReproductiveStatus.NORMAL.name, + val maleStatus: String = MaleReproductiveStatus.NORMAL.name, + val optionalDate: String? = null +) diff --git a/app/src/main/java/com/hsdiary/data/preferences/UserPreferences.kt b/app/src/main/java/com/hsdiary/data/preferences/UserPreferences.kt new file mode 100644 index 0000000..94fce84 --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/preferences/UserPreferences.kt @@ -0,0 +1,57 @@ +package com.hsdiary.data.preferences + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.* +import androidx.datastore.preferences.preferencesDataStore +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject +import javax.inject.Singleton + +private val Context.dataStore: DataStore by preferencesDataStore(name = "hs_diary_prefs") + +@Singleton +class UserPreferences @Inject constructor( + @ApplicationContext private val context: Context +) { + private object Keys { + val ACTIVE_PROFILE_ID = longPreferencesKey("active_profile_id") + val FIRST_DAY_OF_WEEK = intPreferencesKey("first_day_of_week") // 1=Sunday, 2=Monday + val APP_THEME = stringPreferencesKey("app_theme") // LIGHT, DARK, SYSTEM + val ONBOARDING_COMPLETE = booleanPreferencesKey("onboarding_complete") + } + + val activeProfileId: Flow = context.dataStore.data.map { prefs -> + prefs[Keys.ACTIVE_PROFILE_ID] + } + + val firstDayOfWeek: Flow = context.dataStore.data.map { prefs -> + prefs[Keys.FIRST_DAY_OF_WEEK] ?: 1 + } + + val appTheme: Flow = context.dataStore.data.map { prefs -> + prefs[Keys.APP_THEME] ?: "SYSTEM" + } + + val onboardingComplete: Flow = context.dataStore.data.map { prefs -> + prefs[Keys.ONBOARDING_COMPLETE] ?: false + } + + suspend fun setActiveProfileId(id: Long) { + context.dataStore.edit { prefs -> prefs[Keys.ACTIVE_PROFILE_ID] = id } + } + + suspend fun setFirstDayOfWeek(day: Int) { + context.dataStore.edit { prefs -> prefs[Keys.FIRST_DAY_OF_WEEK] = day } + } + + suspend fun setAppTheme(theme: String) { + context.dataStore.edit { prefs -> prefs[Keys.APP_THEME] = theme } + } + + suspend fun setOnboardingComplete(complete: Boolean) { + context.dataStore.edit { prefs -> prefs[Keys.ONBOARDING_COMPLETE] = complete } + } +} diff --git a/app/src/main/java/com/hsdiary/data/repository/CycleRepository.kt b/app/src/main/java/com/hsdiary/data/repository/CycleRepository.kt new file mode 100644 index 0000000..de1dde0 --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/repository/CycleRepository.kt @@ -0,0 +1,62 @@ +package com.hsdiary.data.repository + +import com.hsdiary.data.db.dao.CycleRecordDao +import com.hsdiary.data.db.entity.CycleRecordEntity +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class CycleRepository @Inject constructor(private val dao: CycleRecordDao) { + + fun getCycleRecords(profileId: Long): Flow> = + dao.getCycleRecords(profileId) + + suspend fun getCycleRecordsOnce(profileId: Long): List = + dao.getCycleRecordsOnce(profileId) + + suspend fun getLatestCycleRecord(profileId: Long): CycleRecordEntity? = + dao.getLatestCycleRecord(profileId) + + suspend fun getCurrentCycleRecord(profileId: Long): CycleRecordEntity? = + dao.getCurrentCycleRecord(profileId) + + suspend fun insertCycleRecord(record: CycleRecordEntity): Long = + dao.insertCycleRecord(record) + + suspend fun updateCycleRecord(record: CycleRecordEntity) = + dao.updateCycleRecord(record) + + suspend fun startNewCycle(profileId: Long, startDate: String, predictedStart: String?) { + val existing = dao.getCurrentCycleRecord(profileId) + if (existing != null) { + val length = java.time.LocalDate.parse(startDate) + .toEpochDay() + .minus(java.time.LocalDate.parse(existing.cycleStart).toEpochDay()) + .toInt() + val delta = predictedStart?.let { + java.time.LocalDate.parse(startDate) + .toEpochDay() + .minus(java.time.LocalDate.parse(it).toEpochDay()) + .toInt() + } + dao.updateCycleRecord(existing.copy(cycleEnd = startDate, cycleLength = length, deltaDays = delta)) + } + dao.insertCycleRecord(CycleRecordEntity( + profileId = profileId, + cycleStart = startDate, + predictedStart = predictedStart + )) + } + + suspend fun endCurrentCycle(profileId: Long, endDate: String) { + val current = dao.getCurrentCycleRecord(profileId) ?: return + val length = java.time.LocalDate.parse(endDate) + .toEpochDay() + .minus(java.time.LocalDate.parse(current.cycleStart).toEpochDay()) + .toInt() + dao.updateCycleRecord(current.copy(cycleEnd = endDate, cycleLength = length)) + } + + suspend fun deleteAllForProfile(profileId: Long) = dao.deleteAllForProfile(profileId) +} diff --git a/app/src/main/java/com/hsdiary/data/repository/DayLogRepository.kt b/app/src/main/java/com/hsdiary/data/repository/DayLogRepository.kt new file mode 100644 index 0000000..973ceef --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/repository/DayLogRepository.kt @@ -0,0 +1,67 @@ +package com.hsdiary.data.repository + +import com.hsdiary.data.db.dao.ConditionDao +import com.hsdiary.data.db.dao.ConditionDefinitionDao +import com.hsdiary.data.db.dao.DayLogDao +import com.hsdiary.data.db.entity.ConditionEntryEntity +import com.hsdiary.data.db.entity.DayLogEntity +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class DayLogRepository @Inject constructor( + private val dayLogDao: DayLogDao, + private val conditionDao: ConditionDao, + private val conditionDefinitionDao: ConditionDefinitionDao +) { + fun getDayLogFlow(profileId: Long, date: String): Flow = + dayLogDao.getDayLogFlow(profileId, date) + + fun getDayLogsInRange(profileId: Long, startDate: String, endDate: String): Flow> = + dayLogDao.getDayLogsInRange(profileId, startDate, endDate) + + suspend fun getDayLogsInRangeOnce(profileId: Long, startDate: String, endDate: String): List = + dayLogDao.getDayLogsInRangeOnce(profileId, startDate, endDate) + + suspend fun getOrCreateDayLog(profileId: Long, date: String): DayLogEntity { + val existing = dayLogDao.getDayLog(profileId, date) + if (existing != null) return existing + val newLog = DayLogEntity(profileId = profileId, date = date) + val id = dayLogDao.insertDayLog(newLog) + return newLog.copy(id = id) + } + + suspend fun upsertDayLog(dayLog: DayLogEntity): Long { + return dayLogDao.insertDayLog(dayLog) + } + + suspend fun updateDayLog(dayLog: DayLogEntity) = dayLogDao.updateDayLog(dayLog) + + fun getConditionsForDay(dayLogId: Long): Flow> = + conditionDao.getConditionsForDay(dayLogId) + + suspend fun getConditionsForDayOnce(dayLogId: Long): List = + conditionDao.getConditionsForDayOnce(dayLogId) + + suspend fun setCondition(dayLogId: Long, conditionKey: String, rating: Int) { + conditionDao.deleteConditionByKey(dayLogId, conditionKey) + conditionDao.insertCondition(ConditionEntryEntity(dayLogId = dayLogId, conditionKey = conditionKey, rating = rating)) + } + + suspend fun removeCondition(dayLogId: Long, conditionKey: String) { + conditionDao.deleteConditionByKey(dayLogId, conditionKey) + } + + suspend fun getConditionsInRange(profileId: Long, startDate: String, endDate: String) = + conditionDao.getConditionsInRange(profileId, startDate, endDate) + + suspend fun getDefinitionsForProfile(isFemale: Boolean) = + conditionDefinitionDao.getDefinitionsForProfile(if (isFemale) "FEMALE_ONLY" else "NONE") + + suspend fun getAllDefinitions() = conditionDefinitionDao.getAllDefinitionsOnce() + + suspend fun getPeriodDays(profileId: Long) = dayLogDao.getPeriodDays(profileId) + + suspend fun deleteAllForProfile(profileId: Long) = dayLogDao.deleteAllForProfile(profileId) +} diff --git a/app/src/main/java/com/hsdiary/data/repository/IntimacyRepository.kt b/app/src/main/java/com/hsdiary/data/repository/IntimacyRepository.kt new file mode 100644 index 0000000..cf758ad --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/repository/IntimacyRepository.kt @@ -0,0 +1,28 @@ +package com.hsdiary.data.repository + +import com.hsdiary.data.db.dao.IntimacyLogDao +import com.hsdiary.data.db.entity.IntimacyLogEntity +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class IntimacyRepository @Inject constructor(private val dao: IntimacyLogDao) { + + fun getLogsForDay(date: String, profileId: Long): Flow> = + dao.getLogsForDay(date, profileId) + + suspend fun getLogsForDayOnce(date: String, profileId: Long) = + dao.getLogsForDayOnce(date, profileId) + + suspend fun getDatesWithLogs(profileId: Long, startDate: String, endDate: String): List = + dao.getDatesWithLogs(profileId, startDate, endDate) + + suspend fun insertLog(log: IntimacyLogEntity): Long = dao.insertLog(log) + + suspend fun updateLog(log: IntimacyLogEntity) = dao.updateLog(log) + + suspend fun deleteLog(log: IntimacyLogEntity) = dao.deleteLog(log) + + suspend fun deleteAllForProfile(profileId: Long) = dao.deleteAllForProfile(profileId) +} diff --git a/app/src/main/java/com/hsdiary/data/repository/ProfileRepository.kt b/app/src/main/java/com/hsdiary/data/repository/ProfileRepository.kt new file mode 100644 index 0000000..5cb8bac --- /dev/null +++ b/app/src/main/java/com/hsdiary/data/repository/ProfileRepository.kt @@ -0,0 +1,25 @@ +package com.hsdiary.data.repository + +import com.hsdiary.data.db.dao.ProfileDao +import com.hsdiary.data.db.entity.ProfileEntity +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class ProfileRepository @Inject constructor(private val dao: ProfileDao) { + + fun getAllProfiles(): Flow> = dao.getAllProfiles() + + suspend fun getAllProfilesOnce(): List = dao.getAllProfilesOnce() + + suspend fun getProfileById(id: Long): ProfileEntity? = dao.getProfileById(id) + + suspend fun insertProfile(profile: ProfileEntity): Long = dao.insertProfile(profile) + + suspend fun updateProfile(profile: ProfileEntity) = dao.updateProfile(profile) + + suspend fun deleteProfile(profile: ProfileEntity) = dao.deleteProfile(profile) + + suspend fun getProfileCount(): Int = dao.getProfileCount() +} diff --git a/app/src/main/java/com/hsdiary/di/AppModule.kt b/app/src/main/java/com/hsdiary/di/AppModule.kt new file mode 100644 index 0000000..85c689d --- /dev/null +++ b/app/src/main/java/com/hsdiary/di/AppModule.kt @@ -0,0 +1,24 @@ +package com.hsdiary.di + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import javax.inject.Qualifier +import javax.inject.Singleton + +@Qualifier +@Retention(AnnotationRetention.RUNTIME) +annotation class ApplicationScope + +@Module +@InstallIn(SingletonComponent::class) +object AppModule { + + @Provides + @Singleton + @ApplicationScope + fun provideApplicationScope(): CoroutineScope = CoroutineScope(SupervisorJob()) +} diff --git a/app/src/main/java/com/hsdiary/di/DatabaseModule.kt b/app/src/main/java/com/hsdiary/di/DatabaseModule.kt new file mode 100644 index 0000000..caeb521 --- /dev/null +++ b/app/src/main/java/com/hsdiary/di/DatabaseModule.kt @@ -0,0 +1,32 @@ +package com.hsdiary.di + +import android.content.Context +import androidx.room.Room +import com.hsdiary.data.db.AppDatabase +import com.hsdiary.data.db.dao.* +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object DatabaseModule { + + @Provides + @Singleton + fun provideDatabase(@ApplicationContext context: Context): AppDatabase { + return Room.databaseBuilder(context, AppDatabase::class.java, "hs_diary.db") + .addCallback(AppDatabase.seedCallback) + .build() + } + + @Provides fun provideProfileDao(db: AppDatabase): ProfileDao = db.profileDao() + @Provides fun provideDayLogDao(db: AppDatabase): DayLogDao = db.dayLogDao() + @Provides fun provideConditionDao(db: AppDatabase): ConditionDao = db.conditionDao() + @Provides fun provideCycleRecordDao(db: AppDatabase): CycleRecordDao = db.cycleRecordDao() + @Provides fun provideIntimacyLogDao(db: AppDatabase): IntimacyLogDao = db.intimacyLogDao() + @Provides fun provideConditionDefinitionDao(db: AppDatabase): ConditionDefinitionDao = db.conditionDefinitionDao() +} diff --git a/app/src/main/java/com/hsdiary/domain/CyclePredictionEngine.kt b/app/src/main/java/com/hsdiary/domain/CyclePredictionEngine.kt new file mode 100644 index 0000000..b749811 --- /dev/null +++ b/app/src/main/java/com/hsdiary/domain/CyclePredictionEngine.kt @@ -0,0 +1,159 @@ +package com.hsdiary.domain + +import com.hsdiary.data.db.entity.CycleRecordEntity +import com.hsdiary.data.model.CyclePhase +import com.hsdiary.domain.model.CyclePrediction +import java.time.LocalDate +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.math.roundToInt + +@Singleton +class CyclePredictionEngine @Inject constructor() { + + fun buildPrediction( + records: List, + defaultCycleLength: Int, + today: LocalDate = LocalDate.now(), + rangeStart: LocalDate = today.minusMonths(1), + rangeEnd: LocalDate = today.plusMonths(2) + ): CyclePrediction { + if (records.isEmpty()) return buildDefaultPrediction(defaultCycleLength, today, rangeStart, rangeEnd) + + val completedLengths = records.mapNotNull { it.cycleLength } + val avgLength = if (completedLengths.isEmpty()) defaultCycleLength + else completedLengths.takeLast(12).average().roundToInt() + + val tier = when { + completedLengths.size >= 12 -> 4 + completedLengths.size >= 4 -> 3 + records.isNotEmpty() -> 2 + else -> 1 + } + + val latestStart = records.maxByOrNull { it.cycleStart }?.let { LocalDate.parse(it.cycleStart) } + ?: return buildDefaultPrediction(defaultCycleLength, today, rangeStart, rangeEnd) + + val cycleDay = (today.toEpochDay() - latestStart.toEpochDay()).toInt() + 1 + val nextPeriod = latestStart.plusDays(avgLength.toLong()) + val lutealLength = 14 + val ovulation = latestStart.plusDays((avgLength - lutealLength).toLong()) + val fertileStart = ovulation.minusDays(5) + val fertileEnd = ovulation.plusDays(1) + + val phaseMap = buildPhaseMap( + records = records, + latestStart = latestStart, + avgLength = avgLength, + ovulation = ovulation, + fertileStart = fertileStart, + fertileEnd = fertileEnd, + rangeStart = rangeStart, + rangeEnd = rangeEnd + ) + + val currentPhase = phaseMap[today] ?: CyclePhase.NO_DATA + + return CyclePrediction( + currentCycleStartDate = latestStart, + currentCycleDay = maxOf(1, cycleDay), + currentPhase = currentPhase, + nextPeriodDate = nextPeriod, + fertileWindowStart = fertileStart, + fertileWindowEnd = fertileEnd, + ovulationDate = ovulation, + averageCycleLength = avgLength, + cyclesLogged = records.size, + tier = tier, + daysUntilNextPeriod = (nextPeriod.toEpochDay() - today.toEpochDay()).toInt().takeIf { it >= 0 }, + phaseMap = phaseMap + ) + } + + private fun buildDefaultPrediction( + defaultLength: Int, + today: LocalDate, + rangeStart: LocalDate, + rangeEnd: LocalDate + ): CyclePrediction { + return CyclePrediction( + currentCycleStartDate = null, + currentCycleDay = 0, + currentPhase = CyclePhase.NO_DATA, + nextPeriodDate = null, + fertileWindowStart = null, + fertileWindowEnd = null, + ovulationDate = null, + averageCycleLength = defaultLength, + cyclesLogged = 0, + tier = 1, + daysUntilNextPeriod = null, + phaseMap = emptyMap() + ) + } + + private fun buildPhaseMap( + records: List, + latestStart: LocalDate, + avgLength: Int, + ovulation: LocalDate, + fertileStart: LocalDate, + fertileEnd: LocalDate, + rangeStart: LocalDate, + rangeEnd: LocalDate + ): Map { + val map = mutableMapOf() + + // Mark confirmed period days from actual records + records.forEach { record -> + val start = LocalDate.parse(record.cycleStart) + val end = record.cycleEnd?.let { LocalDate.parse(it) } ?: start.plusDays(4) + var d = start + while (!d.isAfter(end) && !d.isAfter(rangeEnd)) { + if (!d.isBefore(rangeStart)) map[d] = CyclePhase.MENSTRUATION_CONFIRMED + d = d.plusDays(1) + } + } + + // Project forward from latestStart through rangeEnd in cycle increments + var cycleStart = latestStart + while (cycleStart.isBefore(rangeEnd)) { + val cycleOvulation = cycleStart.plusDays((avgLength - 14).toLong()) + val cycleFertileStart = cycleOvulation.minusDays(5) + val cycleFertileEnd = cycleOvulation.plusDays(1) + val cycleEnd = cycleStart.plusDays(avgLength.toLong()) + val periodEnd = cycleStart.plusDays(4) + + // Period days (predicted if future, already marked confirmed if past) + var d = cycleStart + while (!d.isAfter(periodEnd) && !d.isAfter(rangeEnd)) { + if (!d.isBefore(rangeStart) && map[d] == null) { + map[d] = CyclePhase.MENSTRUATION_PREDICTED + } + d = d.plusDays(1) + } + + // Fertile window + d = cycleFertileStart + while (!d.isAfter(cycleFertileEnd) && !d.isAfter(rangeEnd)) { + if (!d.isBefore(rangeStart) && map[d] == null) { + map[d] = if (d == cycleOvulation) CyclePhase.OVULATION_PREDICTED else CyclePhase.FERTILE_WINDOW_PREDICTED + } + d = d.plusDays(1) + } + + // Luteal phase + d = cycleFertileEnd.plusDays(1) + while (!d.isBefore(cycleStart) && !d.isAfter(cycleEnd.minusDays(1)) && !d.isAfter(rangeEnd)) { + if (!d.isBefore(rangeStart) && map[d] == null) { + map[d] = CyclePhase.LUTEAL + } + d = d.plusDays(1) + } + + cycleStart = cycleEnd + } + + return map + } +} diff --git a/app/src/main/java/com/hsdiary/domain/model/CyclePrediction.kt b/app/src/main/java/com/hsdiary/domain/model/CyclePrediction.kt new file mode 100644 index 0000000..f0718c5 --- /dev/null +++ b/app/src/main/java/com/hsdiary/domain/model/CyclePrediction.kt @@ -0,0 +1,24 @@ +package com.hsdiary.domain.model + +import com.hsdiary.data.model.CyclePhase +import java.time.LocalDate + +data class CyclePrediction( + val currentCycleStartDate: LocalDate?, + val currentCycleDay: Int, + val currentPhase: CyclePhase, + val nextPeriodDate: LocalDate?, + val fertileWindowStart: LocalDate?, + val fertileWindowEnd: LocalDate?, + val ovulationDate: LocalDate?, + val averageCycleLength: Int, + val cyclesLogged: Int, + val tier: Int, + val daysUntilNextPeriod: Int?, + val phaseMap: Map +) + +data class DayPhaseInfo( + val phase: CyclePhase, + val cycleDay: Int? +) diff --git a/app/src/main/java/com/hsdiary/ui/calendar/CalendarScreen.kt b/app/src/main/java/com/hsdiary/ui/calendar/CalendarScreen.kt new file mode 100644 index 0000000..dfad647 --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/calendar/CalendarScreen.kt @@ -0,0 +1,330 @@ +package com.hsdiary.ui.calendar + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.TrendingUp +import androidx.compose.material.icons.filled.* +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import com.hsdiary.data.model.CyclePhase +import com.hsdiary.data.model.ProfileType +import com.hsdiary.ui.components.AvatarDot +import com.hsdiary.ui.components.ProfileSwitchSheet +import com.hsdiary.ui.theme.* +import java.time.LocalDate +import java.time.YearMonth +import java.time.format.TextStyle +import java.util.Locale + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun CalendarScreen( + onDayClick: (String) -> Unit, + onInsightsClick: () -> Unit, + onTrendsClick: () -> Unit, + onSettingsClick: () -> Unit, + viewModel: CalendarViewModel = hiltViewModel() +) { + val state by viewModel.uiState.collectAsState() + val activeProfile = state.activeProfile + + Scaffold( + topBar = { + TopAppBar( + title = { + Column { + Text("H&S Diary", style = MaterialTheme.typography.titleLarge) + if (activeProfile != null) { + Text( + activeProfile.name, + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + }, + actions = { + IconButton(onClick = onTrendsClick) { + Icon(Icons.AutoMirrored.Filled.TrendingUp, contentDescription = "Trends") + } + IconButton(onClick = onSettingsClick) { + Icon(Icons.Default.Settings, contentDescription = "Settings") + } + if (activeProfile != null) { + val avatarColor = parseColor(activeProfile.avatarColor) + IconButton(onClick = { viewModel.showProfileSheet() }) { + AvatarDot(name = activeProfile.name, avatarColor = avatarColor, size = 32) + } + } + } + ) + } + ) { padding -> + Column(modifier = Modifier.fillMaxSize().padding(padding)) { + // Context banner (female only) + if (activeProfile?.profileType == ProfileType.FEMALE.name) { + val prediction = state.prediction + ContextBanner( + prediction = prediction, + onClick = onInsightsClick + ) + } + + // Month navigation + MonthHeader( + month = state.currentMonth, + onPrevious = viewModel::previousMonth, + onNext = viewModel::nextMonth + ) + + // Day-of-week headers + val dayHeaders = if (state.firstDayOfWeek == 1) + listOf("S","M","T","W","T","F","S") + else + listOf("M","T","W","T","F","S","S") + Row(Modifier.fillMaxWidth().padding(horizontal = 8.dp)) { + dayHeaders.forEach { h -> + Text( + text = h, + modifier = Modifier.weight(1f), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + + // Calendar grid + val isFemale = activeProfile?.profileType == ProfileType.FEMALE.name + CalendarGrid( + days = state.dayStates, + isFemale = isFemale, + onDayClick = { onDayClick(it.toString()) } + ) + } + } + + if (state.showProfileSheet && state.profiles.size > 1) { + ProfileSwitchSheet( + profiles = viewModel.getProfileSwitchItems(state), + onProfileSelected = viewModel::switchProfile, + onDismiss = viewModel::hideProfileSheet + ) + } +} + +@Composable +private fun ContextBanner( + prediction: com.hsdiary.domain.model.CyclePrediction?, + onClick: () -> Unit +) { + val text = when { + prediction == null || prediction.cyclesLogged == 0 -> + "๐Ÿฉธ Set up your cycle โ€” log your first period to begin" + prediction.currentPhase == CyclePhase.MENSTRUATION_CONFIRMED || + prediction.currentPhase == CyclePhase.MENSTRUATION_PREDICTED -> + "๐Ÿฉธ Period ยท Day ${prediction.currentCycleDay}" + prediction.currentPhase == CyclePhase.OVULATION || + prediction.currentPhase == CyclePhase.OVULATION_PREDICTED -> + "๐ŸŒฟ Ovulation day" + prediction.currentPhase == CyclePhase.FERTILE_WINDOW || + prediction.currentPhase == CyclePhase.FERTILE_WINDOW_PREDICTED -> { + val remaining = prediction.fertileWindowEnd?.let { + (it.toEpochDay() - LocalDate.now().toEpochDay()).toInt() + } ?: 0 + "๐ŸŒฟ Fertile window ยท ~$remaining days remaining" + } + else -> { + val days = prediction.daysUntilNextPeriod + if (days != null) "๐Ÿฉธ Next period in ~$days days ยท Cycle day ${prediction.currentCycleDay}" + else "๐Ÿฉธ Cycle day ${prediction.currentCycleDay}" + } + } + + Surface( + modifier = Modifier.fillMaxWidth().clickable(onClick = onClick), + color = MaterialTheme.colorScheme.primaryContainer, + tonalElevation = 1.dp + ) { + Text( + text = text, + modifier = Modifier.padding(horizontal = 16.dp, vertical = 10.dp), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onPrimaryContainer + ) + } +} + +@Composable +private fun MonthHeader(month: YearMonth, onPrevious: () -> Unit, onNext: () -> Unit) { + Row( + modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp, vertical = 4.dp), + verticalAlignment = Alignment.CenterVertically + ) { + IconButton(onClick = onPrevious) { + Icon(Icons.Default.ChevronLeft, contentDescription = "Previous month") + } + Text( + text = "${month.month.getDisplayName(TextStyle.FULL, Locale.getDefault())} ${month.year}", + modifier = Modifier.weight(1f), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.SemiBold + ) + IconButton(onClick = onNext) { + Icon(Icons.Default.ChevronRight, contentDescription = "Next month") + } + } +} + +@Composable +private fun CalendarGrid( + days: List, + isFemale: Boolean, + onDayClick: (LocalDate) -> Unit +) { + Column(modifier = Modifier.fillMaxWidth().padding(horizontal = 4.dp)) { + days.chunked(7).forEach { week -> + Row(modifier = Modifier.fillMaxWidth()) { + week.forEach { day -> + DayCell( + day = day, + isFemale = isFemale, + onClick = { onDayClick(day.date) }, + modifier = Modifier.weight(1f) + ) + } + } + } + } +} + +@Composable +private fun DayCell( + day: DayState, + isFemale: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + val phaseColor = if (isFemale) phaseColor(day.phase) else null + val textAlpha = if (day.isCurrentMonth) 1f else 0.35f + + Box( + modifier = modifier + .aspectRatio(1f) + .padding(1.dp) + .clip(RoundedCornerShape(8.dp)) + .clickable(onClick = onClick) + ) { + // Phase color band at bottom + if (phaseColor != null) { + Box( + modifier = Modifier + .fillMaxWidth() + .fillMaxHeight(0.25f) + .align(Alignment.BottomCenter) + .background( + phaseColor.copy( + alpha = if (isPredicted(day.phase)) 0.45f else 0.75f + ) + ) + ) + } + + // Today ring + if (day.isToday) { + Box( + modifier = Modifier + .size(28.dp) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.primary) + .align(Alignment.TopCenter) + .offset(y = 3.dp) + ) + } + + Column( + modifier = Modifier.fillMaxSize().padding(2.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + // Day number + Text( + text = day.date.dayOfMonth.toString(), + style = MaterialTheme.typography.bodySmall, + color = if (day.isToday) Color.White else MaterialTheme.colorScheme.onSurface.copy(alpha = textAlpha), + fontWeight = if (day.isToday) FontWeight.Bold else FontWeight.Normal, + modifier = Modifier.padding(top = 4.dp) + ) + + // Icon row + val icons = buildIconList(day, isFemale) + if (icons.isNotEmpty()) { + Row( + modifier = Modifier.padding(top = 1.dp), + horizontalArrangement = Arrangement.Center + ) { + val visibleIcons = if (day.hasIntimacy) icons.take(2) else icons.take(3) + val overflow = icons.size - visibleIcons.size + visibleIcons.forEach { icon -> + Text(icon, fontSize = 9.sp, lineHeight = 10.sp) + } + if (overflow > 0) Text("+$overflow", fontSize = 7.sp, color = MaterialTheme.colorScheme.onSurfaceVariant) + if (day.hasIntimacy) Text("โค๏ธ", fontSize = 9.sp, lineHeight = 10.sp) + } + } + } + } +} + +private fun buildIconList(day: DayState, isFemale: Boolean): List { + val icons = mutableListOf() + if (isFemale && (day.periodActive || day.phase == CyclePhase.MENSTRUATION_CONFIRMED || day.phase == CyclePhase.MENSTRUATION_PREDICTED)) { + icons.add("๐Ÿฉธ") + } + day.conditionKeys.take(3).forEach { key -> + icons.add(conditionIcon(key)) + } + return icons +} + +private fun conditionIcon(key: String): String = when { + key.contains("HEAD") || key.contains("MIGRAINE") -> "โšก" + key.contains("FATIGUE") || key.contains("EXHAUST") -> "๐Ÿ˜ด" + key.contains("NAUSEA") || key.contains("VOMIT") -> "๐Ÿคข" + key.contains("CRAMP") -> "๐Ÿ’ซ" + key.contains("BACK") || key.contains("NECK") || key.contains("JOINT") -> "๐Ÿฆด" + key.contains("MOOD") || key.contains("ANXIOUS") || key.contains("IRRITABLE") -> "๐Ÿ˜ค" + key.contains("HAPPY") || key.contains("CALM") -> "๐Ÿ˜Š" + key.contains("FEVER") || key.contains("CHILL") -> "๐Ÿค’" + else -> "โ€ข" +} + +private fun phaseColor(phase: CyclePhase): Color? = when (phase) { + CyclePhase.MENSTRUATION_CONFIRMED -> PeriodColor + CyclePhase.MENSTRUATION_PREDICTED -> PeriodPredictedColor + CyclePhase.FERTILE_WINDOW, CyclePhase.FERTILE_WINDOW_PREDICTED -> FertileColor + CyclePhase.OVULATION, CyclePhase.OVULATION_PREDICTED -> OvulationColor + CyclePhase.LUTEAL -> LutealColor + else -> null +} + +private fun isPredicted(phase: CyclePhase): Boolean = phase == CyclePhase.MENSTRUATION_PREDICTED || + phase == CyclePhase.FERTILE_WINDOW_PREDICTED || phase == CyclePhase.OVULATION_PREDICTED + +fun parseColor(hex: String): Color = try { + Color(android.graphics.Color.parseColor(hex)) +} catch (e: Exception) { Color(0xFFE91E63) } diff --git a/app/src/main/java/com/hsdiary/ui/calendar/CalendarViewModel.kt b/app/src/main/java/com/hsdiary/ui/calendar/CalendarViewModel.kt new file mode 100644 index 0000000..93ece03 --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/calendar/CalendarViewModel.kt @@ -0,0 +1,207 @@ +package com.hsdiary.ui.calendar + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.hsdiary.data.db.entity.DayLogEntity +import com.hsdiary.data.db.entity.ProfileEntity +import com.hsdiary.data.model.CyclePhase +import com.hsdiary.data.model.ProfileType +import com.hsdiary.data.preferences.UserPreferences +import com.hsdiary.data.repository.CycleRepository +import com.hsdiary.data.repository.DayLogRepository +import com.hsdiary.data.repository.IntimacyRepository +import com.hsdiary.data.repository.ProfileRepository +import com.hsdiary.domain.CyclePredictionEngine +import com.hsdiary.domain.model.CyclePrediction +import com.hsdiary.ui.components.ProfileSwitchItem +import com.hsdiary.ui.theme.AvatarColors +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import java.time.LocalDate +import java.time.YearMonth +import javax.inject.Inject + +data class DayState( + val date: LocalDate, + val isToday: Boolean, + val isCurrentMonth: Boolean, + val periodActive: Boolean, + val phase: CyclePhase, + val conditionKeys: List, + val hasIntimacy: Boolean +) + +data class CalendarUiState( + val activeProfile: ProfileEntity? = null, + val profiles: List = emptyList(), + val currentMonth: YearMonth = YearMonth.now(), + val dayStates: List = emptyList(), + val prediction: CyclePrediction? = null, + val firstDayOfWeek: Int = 1, + val showProfileSheet: Boolean = false +) + +@OptIn(ExperimentalCoroutinesApi::class) +@HiltViewModel +class CalendarViewModel @Inject constructor( + private val profileRepository: ProfileRepository, + private val dayLogRepository: DayLogRepository, + private val cycleRepository: CycleRepository, + private val intimacyRepository: IntimacyRepository, + private val predictionEngine: CyclePredictionEngine, + private val userPreferences: UserPreferences +) : ViewModel() { + + private val _currentMonth = MutableStateFlow(YearMonth.now()) + private val _showProfileSheet = MutableStateFlow(false) + + val uiState: StateFlow = combine( + userPreferences.activeProfileId, + profileRepository.getAllProfiles(), + _currentMonth, + userPreferences.firstDayOfWeek, + _showProfileSheet + ) { activeId, profiles, month, fdow, showSheet -> + Triple(activeId to profiles, month to fdow, showSheet) + }.flatMapLatest { (profileData, monthData, showSheet) -> + val (activeId, profiles) = profileData + val (month, fdow) = monthData + val activeProfile = profiles.find { it.id == activeId } ?: profiles.firstOrNull() + + if (activeProfile == null) { + return@flatMapLatest flowOf(CalendarUiState(showProfileSheet = showSheet)) + } + + val isFemale = activeProfile.profileType == ProfileType.FEMALE.name + val rangeStart = month.atDay(1).minusDays(6) + val rangeEnd = month.atEndOfMonth().plusDays(6) + + combine( + dayLogRepository.getDayLogsInRange(activeProfile.id, rangeStart.toString(), rangeEnd.toString()), + cycleRepository.getCycleRecords(activeProfile.id) + ) { dayLogs, cycleRecords -> + val today = LocalDate.now() + val prediction = if (isFemale) { + predictionEngine.buildPrediction( + records = cycleRecords, + defaultCycleLength = activeProfile.cycleLengthDefault, + today = today, + rangeStart = rangeStart, + rangeEnd = rangeEnd + ) + } else null + + val intimacyDates = intimacyRepository.getDatesWithLogs( + activeProfile.id, rangeStart.toString(), rangeEnd.toString() + ).toSet() + + val dayLogMap = dayLogs.associateBy { it.date } + val conditionMap = buildConditionMap(dayLogs, activeProfile.id, rangeStart.toString(), rangeEnd.toString()) + + val days = buildCalendarDays(month, fdow, today, dayLogMap, conditionMap, intimacyDates, prediction) + + CalendarUiState( + activeProfile = activeProfile, + profiles = profiles, + currentMonth = month, + dayStates = days, + prediction = prediction, + firstDayOfWeek = fdow, + showProfileSheet = showSheet + ) + } + }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), CalendarUiState()) + + private suspend fun buildConditionMap( + dayLogs: List, + profileId: Long, + startDate: String, + endDate: String + ): Map> { + val allConditions = dayLogRepository.getConditionsInRange(profileId, startDate, endDate) + val dayLogById = dayLogs.associateBy { it.id } + return allConditions + .groupBy { entry -> dayLogById[entry.dayLogId]?.date ?: "" } + .filter { it.key.isNotEmpty() } + .mapValues { (_, conds) -> conds.map { it.conditionKey } } + } + + private fun buildCalendarDays( + month: YearMonth, + firstDayOfWeek: Int, + today: LocalDate, + dayLogMap: Map, + conditionMap: Map>, + intimacyDates: Set, + prediction: CyclePrediction? + ): List { + val firstOfMonth = month.atDay(1) + // offset: how many blank days before the 1st + val dayOfWeek = firstOfMonth.dayOfWeek.value % 7 // 0=Sun..6=Sat + val offset = if (firstDayOfWeek == 1) dayOfWeek else (dayOfWeek + 6) % 7 + val result = mutableListOf() + + // preceding month days + for (i in offset - 1 downTo 0) { + val date = firstOfMonth.minusDays(i.toLong() + 1) + result.add(makeDayState(date, today, false, dayLogMap, conditionMap, intimacyDates, prediction)) + } + // current month + for (day in 1..month.lengthOfMonth()) { + val date = month.atDay(day) + result.add(makeDayState(date, today, true, dayLogMap, conditionMap, intimacyDates, prediction)) + } + // trailing days to complete last row + val remaining = (7 - result.size % 7) % 7 + for (i in 1..remaining) { + val date = month.atEndOfMonth().plusDays(i.toLong()) + result.add(makeDayState(date, today, false, dayLogMap, conditionMap, intimacyDates, prediction)) + } + return result + } + + private fun makeDayState( + date: LocalDate, + today: LocalDate, + isCurrentMonth: Boolean, + dayLogMap: Map, + conditionMap: Map>, + intimacyDates: Set, + prediction: CyclePrediction? + ): DayState { + val key = date.toString() + val log = dayLogMap[key] + val phase = prediction?.phaseMap?.get(date) ?: CyclePhase.NO_DATA + return DayState( + date = date, + isToday = date == today, + isCurrentMonth = isCurrentMonth, + periodActive = log?.periodActive ?: false, + phase = phase, + conditionKeys = conditionMap[key] ?: emptyList(), + hasIntimacy = intimacyDates.contains(key) + ) + } + + fun previousMonth() { _currentMonth.value = _currentMonth.value.minusMonths(1) } + fun nextMonth() { _currentMonth.value = _currentMonth.value.plusMonths(1) } + + fun showProfileSheet() { _showProfileSheet.value = true } + fun hideProfileSheet() { _showProfileSheet.value = false } + + fun switchProfile(profileId: Long) { + viewModelScope.launch { userPreferences.setActiveProfileId(profileId) } + } + + fun getProfileSwitchItems(state: CalendarUiState): List { + return state.profiles.map { p -> + val color = try { + android.graphics.Color.parseColor(p.avatarColor) + .let { androidx.compose.ui.graphics.Color(it) } + } catch (e: Exception) { AvatarColors[0] } + ProfileSwitchItem(p.id, p.name, color, p.id == state.activeProfile?.id) + } + } +} diff --git a/app/src/main/java/com/hsdiary/ui/components/ProfileChip.kt b/app/src/main/java/com/hsdiary/ui/components/ProfileChip.kt new file mode 100644 index 0000000..c739961 --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/components/ProfileChip.kt @@ -0,0 +1,77 @@ +package com.hsdiary.ui.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun ProfileChip( + name: String, + avatarColor: Color, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + Row( + modifier = modifier + .clip(MaterialTheme.shapes.medium) + .clickable(onClick = onClick) + .padding(horizontal = 8.dp, vertical = 4.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(6.dp) + ) { + Box( + modifier = Modifier + .size(28.dp) + .clip(CircleShape) + .background(avatarColor), + contentAlignment = Alignment.Center + ) { + Text( + text = name.take(1).uppercase(), + color = Color.White, + fontSize = 13.sp, + fontWeight = FontWeight.Bold + ) + } + Text( + text = name, + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Medium + ) + } +} + +@Composable +fun AvatarDot( + name: String, + avatarColor: Color, + size: Int = 36, + modifier: Modifier = Modifier +) { + Box( + modifier = modifier + .size(size.dp) + .clip(CircleShape) + .background(avatarColor), + contentAlignment = Alignment.Center + ) { + Text( + text = name.take(1).uppercase(), + color = Color.White, + fontSize = (size * 0.38).sp, + fontWeight = FontWeight.Bold + ) + } +} diff --git a/app/src/main/java/com/hsdiary/ui/components/ProfileSwitchSheet.kt b/app/src/main/java/com/hsdiary/ui/components/ProfileSwitchSheet.kt new file mode 100644 index 0000000..0879df2 --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/components/ProfileSwitchSheet.kt @@ -0,0 +1,78 @@ +package com.hsdiary.ui.components + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp + +data class ProfileSwitchItem( + val id: Long, + val name: String, + val avatarColor: Color, + val isActive: Boolean +) + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ProfileSwitchSheet( + profiles: List, + onProfileSelected: (Long) -> Unit, + onDismiss: () -> Unit +) { + var confirmTarget by remember { mutableStateOf(null) } + + ModalBottomSheet(onDismissRequest = onDismiss) { + Column(modifier = Modifier.padding(horizontal = 24.dp).padding(bottom = 32.dp)) { + Text( + text = "Switch Profile", + style = MaterialTheme.typography.titleMedium, + modifier = Modifier.padding(bottom = 16.dp) + ) + profiles.forEach { profile -> + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { + if (!profile.isActive) confirmTarget = profile + else onDismiss() + } + .padding(vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + AvatarDot(name = profile.name, avatarColor = profile.avatarColor) + Text( + text = profile.name, + style = MaterialTheme.typography.bodyLarge, + modifier = Modifier.weight(1f) + ) + if (profile.isActive) { + Badge { Text("Active") } + } + } + } + } + } + + confirmTarget?.let { target -> + AlertDialog( + onDismissRequest = { confirmTarget = null }, + title = { Text("Switch Profile") }, + text = { Text("Switch to ${target.name}?") }, + confirmButton = { + TextButton(onClick = { + onProfileSelected(target.id) + confirmTarget = null + onDismiss() + }) { Text("Switch") } + }, + dismissButton = { + TextButton(onClick = { confirmTarget = null }) { Text("Cancel") } + } + ) + } +} diff --git a/app/src/main/java/com/hsdiary/ui/daydetail/DayDetailScreen.kt b/app/src/main/java/com/hsdiary/ui/daydetail/DayDetailScreen.kt new file mode 100644 index 0000000..e1846b2 --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/daydetail/DayDetailScreen.kt @@ -0,0 +1,475 @@ +package com.hsdiary.ui.daydetail + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.* +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import com.hsdiary.data.db.entity.ConditionDefinitionEntity +import com.hsdiary.data.db.entity.IntimacyLogEntity +import com.hsdiary.data.model.CyclePhase +import java.time.LocalDate +import java.time.format.DateTimeFormatter +import java.util.Locale + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DayDetailScreen( + date: String, + onBack: () -> Unit, + viewModel: DayDetailViewModel = hiltViewModel() +) { + val state by viewModel.uiState.collectAsState() + var savedSnackbar by remember { mutableStateOf(false) } + val snackbarHostState = remember { SnackbarHostState() } + + LaunchedEffect(savedSnackbar) { + if (savedSnackbar) { + snackbarHostState.showSnackbar("Saved") + savedSnackbar = false + } + } + + val dateLabel = remember(date) { + LocalDate.parse(date).format(DateTimeFormatter.ofPattern("EEEE, MMMM d, yyyy", Locale.getDefault())) + } + + BackHandler { + if (state.isDirty) { + viewModel.saveAndExit() + savedSnackbar = true + } + onBack() + } + + Scaffold( + snackbarHost = { SnackbarHost(snackbarHostState) }, + topBar = { + TopAppBar( + title = { Text(dateLabel, style = MaterialTheme.typography.titleMedium) }, + navigationIcon = { + IconButton(onClick = { + if (state.isDirty) viewModel.saveAndExit() + onBack() + }) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, "Back") + } + } + ) + } + ) { padding -> + LazyColumn( + modifier = Modifier.fillMaxSize().padding(padding), + contentPadding = PaddingValues(bottom = 32.dp) + ) { + // Cycle section (female only) + if (state.isFemale) { + item { CycleSection(state = state, onTogglePeriod = viewModel::togglePeriod) } + item { HorizontalDivider() } + } + + // Conditions section + item { + ConditionsSection( + definitions = state.definitions, + selectedConditions = state.conditions, + onToggle = viewModel::toggleCondition, + onRatingChange = viewModel::setConditionRating + ) + } + + // Notes + item { + NotesSection( + notes = state.notes, + onNotesChange = viewModel::updateNotes, + onSave = viewModel::saveNotes + ) + } + + item { HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp)) } + + // Intimacy section + item { + IntimacySection( + logs = state.intimacyLogs, + profiles = state.allProfiles, + activeProfileId = state.activeProfile?.id ?: 0L, + isFemaleInFertileWindow = state.isFemale && ( + state.currentPhase == CyclePhase.FERTILE_WINDOW || + state.currentPhase == CyclePhase.OVULATION + ), + onAdd = { pType, pName, time, protected -> + viewModel.addIntimacyLog(pType, pName, time, protected) + }, + onDelete = viewModel::deleteIntimacyLog + ) + } + } + } +} + +@Composable +private fun CycleSection(state: DayDetailUiState, onTogglePeriod: () -> Unit) { + Column(modifier = Modifier.padding(16.dp)) { + val phaseLabel = when (state.currentPhase) { + CyclePhase.MENSTRUATION_CONFIRMED -> "Menstruation" + CyclePhase.MENSTRUATION_PREDICTED -> "Predicted: Menstruation" + CyclePhase.FERTILE_WINDOW -> "Fertile Window" + CyclePhase.FERTILE_WINDOW_PREDICTED -> "Predicted: Fertile Window" + CyclePhase.OVULATION, CyclePhase.OVULATION_PREDICTED -> "Ovulation" + CyclePhase.LUTEAL -> "Luteal Phase" + CyclePhase.FOLLICULAR -> "Follicular Phase" + else -> "No cycle data" + } + if (state.cycleDay > 0) { + Text( + "Day ${state.cycleDay} of cycle ยท $phaseLabel", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + Spacer(Modifier.height(12.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text("Period today", style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.Medium) + Switch(checked = state.periodActive, onCheckedChange = { onTogglePeriod() }) + } + if (state.currentPhase == CyclePhase.MENSTRUATION_PREDICTED && !state.periodActive) { + Spacer(Modifier.height(8.dp)) + OutlinedCard(modifier = Modifier.fillMaxWidth()) { + Row( + modifier = Modifier.padding(12.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Icon(Icons.Default.Info, contentDescription = null, tint = MaterialTheme.colorScheme.primary, modifier = Modifier.size(16.dp)) + Text("Period predicted today โ€” tap the toggle to confirm", style = MaterialTheme.typography.bodySmall) + } + } + } + } +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +private fun ConditionsSection( + definitions: List, + selectedConditions: Map, + onToggle: (String) -> Unit, + onRatingChange: (String, Int) -> Unit +) { + val grouped = remember(definitions) { + definitions.groupBy { it.category } + } + var expandedCategories by remember { mutableStateOf(setOf()) } + + Column(modifier = Modifier.padding(16.dp)) { + Text("Symptoms", style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold) + Spacer(Modifier.height(12.dp)) + + grouped.forEach { (category, items) -> + val categoryLabel = category.replace("_", " ").lowercase() + .replaceFirstChar { it.uppercase() } + val isExpanded = category in expandedCategories + val hasSelected = items.any { selectedConditions.containsKey(it.conditionKey) } + + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { + expandedCategories = if (isExpanded) + expandedCategories - category + else + expandedCategories + category + } + .padding(vertical = 8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = categoryLabel, + style = MaterialTheme.typography.labelLarge, + color = if (hasSelected) MaterialTheme.colorScheme.primary + else MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.weight(1f) + ) + if (hasSelected) { + Badge(containerColor = MaterialTheme.colorScheme.primary) { + Text("${items.count { selectedConditions.containsKey(it.conditionKey) }}") + } + } + Icon( + if (isExpanded) Icons.Default.ExpandLess else Icons.Default.ExpandMore, + contentDescription = null, + modifier = Modifier.size(20.dp) + ) + } + + if (isExpanded) { + FlowRow( + modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + items.forEach { def -> + val selected = selectedConditions.containsKey(def.conditionKey) + FilterChip( + selected = selected, + onClick = { onToggle(def.conditionKey) }, + label = { Text(def.displayName, style = MaterialTheme.typography.bodySmall) } + ) + } + } + // Rating row for selected items in this category + items.filter { selectedConditions.containsKey(it.conditionKey) }.forEach { def -> + val rating = selectedConditions[def.conditionKey] ?: 3 + RatingRow( + label = def.displayName, + rating = rating, + onRatingChange = { onRatingChange(def.conditionKey, it) } + ) + } + } + } + } +} + +@Composable +private fun RatingRow(label: String, rating: Int, onRatingChange: (Int) -> Unit) { + Row( + modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp, horizontal = 4.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text(label, style = MaterialTheme.typography.bodySmall, modifier = Modifier.width(120.dp)) + Row(horizontalArrangement = Arrangement.spacedBy(4.dp)) { + (1..5).forEach { i -> + Box( + modifier = Modifier + .size(22.dp) + .background( + if (i <= rating) MaterialTheme.colorScheme.primary + else MaterialTheme.colorScheme.surfaceVariant, + shape = RoundedCornerShape(4.dp) + ) + .clickable { onRatingChange(i) }, + contentAlignment = Alignment.Center + ) { + Text( + i.toString(), + style = MaterialTheme.typography.labelSmall, + color = if (i <= rating) MaterialTheme.colorScheme.onPrimary + else MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + } + } +} + +@Composable +private fun NotesSection(notes: String, onNotesChange: (String) -> Unit, onSave: () -> Unit) { + Column(modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)) { + OutlinedTextField( + value = notes, + onValueChange = { if (it.length <= 256) onNotesChange(it) }, + label = { Text("Notes") }, + modifier = Modifier.fillMaxWidth(), + minLines = 2, + maxLines = 4, + supportingText = { Text("${notes.length}/256") } + ) + } +} + +@Composable +private fun IntimacySection( + logs: List, + profiles: List, + activeProfileId: Long, + isFemaleInFertileWindow: Boolean, + onAdd: (String, String?, String?, Boolean) -> Unit, + onDelete: (IntimacyLogEntity) -> Unit +) { + var isExpanded by remember { mutableStateOf(true) } + var showAddForm by remember { mutableStateOf(false) } + + Column(modifier = Modifier.padding(16.dp)) { + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { isExpanded = !isExpanded } + .padding(vertical = 4.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + "Intimacy", + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.SemiBold, + modifier = Modifier.weight(1f) + ) + Icon( + if (isExpanded) Icons.Default.ExpandLess else Icons.Default.ExpandMore, + contentDescription = null + ) + } + + if (isExpanded) { + logs.forEach { log -> + IntimacyLogCard( + log = log, + isFemaleInFertileWindow = isFemaleInFertileWindow, + onDelete = { onDelete(log) } + ) + } + + if (showAddForm) { + AddIntimacyForm( + profiles = profiles, + activeProfileId = activeProfileId, + onConfirm = { pType, pName, time, protected -> + onAdd(pType, pName, time, protected) + showAddForm = false + }, + onCancel = { showAddForm = false } + ) + } else { + TextButton( + onClick = { showAddForm = true }, + modifier = Modifier.padding(top = 4.dp) + ) { + Icon(Icons.Default.Add, contentDescription = null, modifier = Modifier.size(16.dp)) + Spacer(Modifier.width(4.dp)) + Text("Add encounter") + } + } + } + } +} + +@Composable +private fun IntimacyLogCard( + log: IntimacyLogEntity, + isFemaleInFertileWindow: Boolean, + onDelete: () -> Unit +) { + OutlinedCard(modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp)) { + Row( + modifier = Modifier.padding(12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text("โค๏ธ ยท ${log.participantName ?: log.participantType} ยท ${log.timeOfDay ?: ""} ยท ${if (log.protected) "Protected" else "Unprotected"}", + style = MaterialTheme.typography.bodySmall, + modifier = Modifier.weight(1f) + ) + IconButton(onClick = onDelete, modifier = Modifier.size(20.dp)) { + Icon(Icons.Default.Close, contentDescription = "Delete", modifier = Modifier.size(14.dp)) + } + } + if (isFemaleInFertileWindow && !log.protected) { + Text( + "๐ŸŒฟ Unprotected ยท Fertile window", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.secondary, + modifier = Modifier.padding(start = 12.dp, bottom = 8.dp) + ) + } + } +} + +@Composable +private fun AddIntimacyForm( + profiles: List, + activeProfileId: Long, + onConfirm: (String, String?, String?, Boolean) -> Unit, + onCancel: () -> Unit +) { + var participantType by remember { mutableStateOf("OTHER") } + var participantName by remember { mutableStateOf("") } + var timeOfDay by remember { mutableStateOf("") } + var protected by remember { mutableStateOf(true) } + + val otherProfile = profiles.firstOrNull { it.id != activeProfileId } + + Card(modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp)) { + Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp)) { + Text("New encounter", style = MaterialTheme.typography.titleSmall) + + // Participant selector + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + if (otherProfile != null) { + FilterChip( + selected = participantType == "PARTNER", + onClick = { participantType = "PARTNER"; participantName = otherProfile.name }, + label = { Text(otherProfile.name) } + ) + } + FilterChip( + selected = participantType == "OTHER", + onClick = { participantType = "OTHER"; participantName = "" }, + label = { Text("Other") } + ) + } + if (participantType == "OTHER") { + OutlinedTextField( + value = participantName, + onValueChange = { if (it.length <= 32) participantName = it }, + label = { Text("Name (optional)") }, + singleLine = true, + modifier = Modifier.fillMaxWidth() + ) + } + OutlinedTextField( + value = timeOfDay, + onValueChange = { timeOfDay = it }, + label = { Text("Time (optional, HH:MM)") }, + singleLine = true, + modifier = Modifier.fillMaxWidth() + ) + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text("Protected", style = MaterialTheme.typography.bodyMedium) + Switch(checked = protected, onCheckedChange = { protected = it }) + } + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + OutlinedButton(onClick = onCancel, modifier = Modifier.weight(1f)) { Text("Cancel") } + Button( + onClick = { + onConfirm( + participantType, + participantName.ifBlank { null }, + timeOfDay.ifBlank { null }, + protected + ) + }, + modifier = Modifier.weight(1f) + ) { Text("Add") } + } + } + } +} + +@Composable +private fun BackHandler(onBack: () -> Unit) { + androidx.activity.compose.BackHandler(onBack = onBack) +} diff --git a/app/src/main/java/com/hsdiary/ui/daydetail/DayDetailViewModel.kt b/app/src/main/java/com/hsdiary/ui/daydetail/DayDetailViewModel.kt new file mode 100644 index 0000000..25175b6 --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/daydetail/DayDetailViewModel.kt @@ -0,0 +1,206 @@ +package com.hsdiary.ui.daydetail + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.hsdiary.data.db.entity.ConditionDefinitionEntity +import com.hsdiary.data.db.entity.DayLogEntity +import com.hsdiary.data.db.entity.IntimacyLogEntity +import com.hsdiary.data.db.entity.ProfileEntity +import com.hsdiary.data.model.CyclePhase +import com.hsdiary.data.model.ProfileType +import com.hsdiary.data.preferences.UserPreferences +import com.hsdiary.data.repository.CycleRepository +import com.hsdiary.data.repository.DayLogRepository +import com.hsdiary.data.repository.IntimacyRepository +import com.hsdiary.data.repository.ProfileRepository +import com.hsdiary.domain.CyclePredictionEngine +import com.hsdiary.domain.model.CyclePrediction +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import java.time.LocalDate +import javax.inject.Inject + +data class DayDetailUiState( + val date: LocalDate = LocalDate.now(), + val activeProfile: ProfileEntity? = null, + val allProfiles: List = emptyList(), + val dayLog: DayLogEntity? = null, + val periodActive: Boolean = false, + val notes: String = "", + val conditions: Map = emptyMap(), // key -> rating + val definitions: List = emptyList(), + val intimacyLogs: List = emptyList(), + val prediction: CyclePrediction? = null, + val isFemale: Boolean = false, + val cycleDay: Int = 0, + val currentPhase: CyclePhase = CyclePhase.NO_DATA, + val showPeriodConfirmPrompt: Boolean = false, + val predictedPeriodDelta: Int = 0, + val isDirty: Boolean = false +) + +@HiltViewModel +class DayDetailViewModel @Inject constructor( + savedStateHandle: SavedStateHandle, + private val profileRepository: ProfileRepository, + private val dayLogRepository: DayLogRepository, + private val cycleRepository: CycleRepository, + private val intimacyRepository: IntimacyRepository, + private val predictionEngine: CyclePredictionEngine, + private val userPreferences: UserPreferences +) : ViewModel() { + + private val dateStr: String = savedStateHandle["date"] ?: LocalDate.now().toString() + val date: LocalDate = LocalDate.parse(dateStr) + + private val _uiState = MutableStateFlow(DayDetailUiState(date = date)) + val uiState: StateFlow = _uiState.asStateFlow() + + init { + viewModelScope.launch { loadData() } + } + + private suspend fun loadData() { + val activeId = userPreferences.activeProfileId.first() + val profiles = profileRepository.getAllProfilesOnce() + val activeProfile = profiles.find { it.id == activeId } ?: profiles.firstOrNull() ?: return + val isFemale = activeProfile.profileType == ProfileType.FEMALE.name + + val dayLog = dayLogRepository.getOrCreateDayLog(activeProfile.id, dateStr) + val conditions = dayLogRepository.getConditionsForDayOnce(dayLog.id) + .associate { it.conditionKey to it.rating } + val defsToShow = dayLogRepository.getDefinitionsForProfile(isFemale) + + val intimacyLogs = intimacyRepository.getLogsForDayOnce(dateStr, activeProfile.id) + + val cycleRecords = cycleRepository.getCycleRecordsOnce(activeProfile.id) + val prediction = if (isFemale) { + predictionEngine.buildPrediction(cycleRecords, activeProfile.cycleLengthDefault, LocalDate.now()) + } else null + + val phase = prediction?.phaseMap?.get(date) ?: CyclePhase.NO_DATA + val cycleDay = if (isFemale && prediction?.currentCycleStartDate != null) { + maxOf(1, (date.toEpochDay() - prediction.currentCycleStartDate.toEpochDay()).toInt() + 1) + } else 0 + + val predictedStart = prediction?.nextPeriodDate + if (predictedStart != null && dayLog.periodActive) { + (date.toEpochDay() - predictedStart.toEpochDay()).toInt() + } else 0 + + _uiState.value = DayDetailUiState( + date = date, + activeProfile = activeProfile, + allProfiles = profiles, + dayLog = dayLog, + periodActive = dayLog.periodActive, + notes = dayLog.notes ?: "", + conditions = conditions, + definitions = defsToShow, + intimacyLogs = intimacyLogs, + prediction = prediction, + isFemale = isFemale, + cycleDay = cycleDay, + currentPhase = phase + ) + + // observe intimacy logs reactively + intimacyRepository.getLogsForDay(dateStr, activeProfile.id) + .onEach { logs -> _uiState.value = _uiState.value.copy(intimacyLogs = logs) } + .launchIn(viewModelScope) + } + + fun togglePeriod() { + val current = _uiState.value.periodActive + val newActive = !current + viewModelScope.launch { + val state = _uiState.value + val dayLog = state.dayLog ?: return@launch + val updatedLog = dayLog.copy(periodActive = newActive) + dayLogRepository.upsertDayLog(updatedLog) + _uiState.value = state.copy(periodActive = newActive, dayLog = updatedLog, isDirty = true) + + if (newActive && state.isFemale) { + val predictedStart = state.prediction?.nextPeriodDate + cycleRepository.startNewCycle( + profileId = dayLog.profileId, + startDate = dateStr, + predictedStart = predictedStart?.toString() + ) + } + } + } + + fun toggleCondition(conditionKey: String) { + viewModelScope.launch { + val state = _uiState.value + val dayLog = state.dayLog ?: return@launch + val current = state.conditions.toMutableMap() + if (current.containsKey(conditionKey)) { + dayLogRepository.removeCondition(dayLog.id, conditionKey) + current.remove(conditionKey) + } else { + dayLogRepository.setCondition(dayLog.id, conditionKey, 3) + current[conditionKey] = 3 + } + _uiState.value = state.copy(conditions = current, isDirty = true) + } + } + + fun setConditionRating(conditionKey: String, rating: Int) { + viewModelScope.launch { + val state = _uiState.value + val dayLog = state.dayLog ?: return@launch + dayLogRepository.setCondition(dayLog.id, conditionKey, rating) + val current = state.conditions.toMutableMap() + current[conditionKey] = rating + _uiState.value = state.copy(conditions = current, isDirty = true) + } + } + + fun updateNotes(notes: String) { + _uiState.value = _uiState.value.copy(notes = notes, isDirty = true) + } + + fun saveNotes() { + viewModelScope.launch { + val state = _uiState.value + val dayLog = state.dayLog ?: return@launch + dayLogRepository.upsertDayLog(dayLog.copy(notes = state.notes.ifBlank { null })) + } + } + + fun addIntimacyLog(participantType: String, participantName: String?, timeOfDay: String?, protected: Boolean) { + viewModelScope.launch { + val state = _uiState.value + val profileId = state.activeProfile?.id ?: return@launch + val shared = participantType != "OTHER" + intimacyRepository.insertLog( + IntimacyLogEntity( + date = dateStr, + ownerProfileId = profileId, + participantType = participantType, + participantName = participantName, + timeOfDay = timeOfDay, + protected = protected, + shared = shared + ) + ) + _uiState.value = state.copy(isDirty = true) + } + } + + fun deleteIntimacyLog(log: IntimacyLogEntity) { + viewModelScope.launch { intimacyRepository.deleteLog(log) } + } + + fun saveAndExit() { + viewModelScope.launch { + val state = _uiState.value + val dayLog = state.dayLog ?: return@launch + dayLogRepository.upsertDayLog(dayLog.copy(notes = state.notes.ifBlank { null })) + } + } +} diff --git a/app/src/main/java/com/hsdiary/ui/insights/CycleInsightsScreen.kt b/app/src/main/java/com/hsdiary/ui/insights/CycleInsightsScreen.kt new file mode 100644 index 0000000..14eec3e --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/insights/CycleInsightsScreen.kt @@ -0,0 +1,207 @@ +package com.hsdiary.ui.insights + +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import com.hsdiary.data.model.CyclePhase +import com.hsdiary.domain.model.CyclePrediction +import java.time.format.DateTimeFormatter +import java.util.Locale + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun CycleInsightsScreen( + onBack: () -> Unit, + viewModel: CycleInsightsViewModel = hiltViewModel() +) { + val state by viewModel.uiState.collectAsState() + + Scaffold( + topBar = { + TopAppBar( + title = { Text("Cycle Insights") }, + navigationIcon = { + IconButton(onClick = onBack) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, "Back") + } + } + ) + } + ) { padding -> + if (state.isLoading) { + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + CircularProgressIndicator() + } + return@Scaffold + } + + val prediction = state.prediction + if (prediction == null || prediction.cyclesLogged == 0) { + Box( + Modifier.fillMaxSize().padding(padding).padding(32.dp), + contentAlignment = Alignment.Center + ) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Text("๐Ÿฉธ", style = MaterialTheme.typography.displayMedium) + Spacer(Modifier.height(16.dp)) + Text("No cycle data yet", style = MaterialTheme.typography.titleMedium) + Spacer(Modifier.height(8.dp)) + Text( + "Log your first period on the calendar to begin tracking.", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + return@Scaffold + } + + Column( + modifier = Modifier + .fillMaxSize() + .padding(padding) + .verticalScroll(rememberScrollState()) + .padding(horizontal = 16.dp, vertical = 8.dp), + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + // Current phase card + ElevatedCard(modifier = Modifier.fillMaxWidth()) { + Column(modifier = Modifier.padding(16.dp)) { + Text("Current Cycle", style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.primary) + Spacer(Modifier.height(8.dp)) + val phaseText = when (prediction.currentPhase) { + CyclePhase.MENSTRUATION_CONFIRMED, CyclePhase.MENSTRUATION_PREDICTED -> "๐Ÿฉธ Menstruation" + CyclePhase.FERTILE_WINDOW, CyclePhase.FERTILE_WINDOW_PREDICTED -> "๐ŸŒฟ Fertile Window" + CyclePhase.OVULATION, CyclePhase.OVULATION_PREDICTED -> "๐ŸŒฟ Ovulation Day" + CyclePhase.LUTEAL -> "๐ŸŒ™ Luteal Phase" + CyclePhase.FOLLICULAR -> "๐ŸŒฑ Follicular Phase" + else -> "โ€”" + } + Text(phaseText, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.SemiBold) + if (prediction.currentCycleDay > 0) { + Text("Day ${prediction.currentCycleDay}", style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) + } + } + } + + // Stats row + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(12.dp)) { + StatCard( + label = "Avg Cycle", + value = "${prediction.averageCycleLength} days", + modifier = Modifier.weight(1f) + ) + StatCard( + label = "Cycles Logged", + value = "${prediction.cyclesLogged}", + modifier = Modifier.weight(1f) + ) + StatCard( + label = "Prediction", + value = "Tier ${prediction.tier}", + modifier = Modifier.weight(1f) + ) + } + + // Next period + prediction.nextPeriodDate?.let { next -> + ElevatedCard(modifier = Modifier.fillMaxWidth()) { + Column(modifier = Modifier.padding(16.dp)) { + Text("Upcoming", style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.primary) + Spacer(Modifier.height(8.dp)) + val fmt = DateTimeFormatter.ofPattern("MMMM d", Locale.getDefault()) + Text("Next period: ${next.format(fmt)}", style = MaterialTheme.typography.bodyLarge) + prediction.daysUntilNextPeriod?.let { days -> + Text("In ~$days days", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) + } + prediction.fertileWindowStart?.let { fw -> + val fwEnd = prediction.fertileWindowEnd + Text( + "Fertile window: ${fw.format(fmt)} โ€“ ${fwEnd?.format(fmt) ?: ""}", + style = MaterialTheme.typography.bodyMedium + ) + } + } + } + } + + // Cycle length bar chart + if (state.recentCycles.size >= 2) { + ElevatedCard(modifier = Modifier.fillMaxWidth()) { + Column(modifier = Modifier.padding(16.dp)) { + Text("Cycle History", style = MaterialTheme.typography.labelLarge, color = MaterialTheme.colorScheme.primary) + Spacer(Modifier.height(12.dp)) + CycleLengthBarChart(cycles = state.recentCycles.mapNotNull { it.cycleLength }) + } + } + } + } + } +} + +@Composable +private fun StatCard(label: String, value: String, modifier: Modifier = Modifier) { + ElevatedCard(modifier = modifier) { + Column( + modifier = Modifier.padding(12.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text(value, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold) + Text(label, style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant) + } + } +} + +@Composable +private fun CycleLengthBarChart(cycles: List) { + if (cycles.isEmpty()) return + val maxLen = cycles.max().toFloat() + val barColor = MaterialTheme.colorScheme.primary + val avgColor = MaterialTheme.colorScheme.secondary + val avg = cycles.average().toFloat() + + Canvas( + modifier = Modifier + .fillMaxWidth() + .height(100.dp) + ) { + val barWidth = (size.width / (cycles.size * 1.5f)) + val spacing = barWidth * 0.5f + cycles.forEachIndexed { i, length -> + val barHeight = (length / maxLen) * size.height * 0.85f + val x = i * (barWidth + spacing) + drawRect( + color = barColor, + topLeft = Offset(x, size.height - barHeight), + size = Size(barWidth, barHeight) + ) + } + // average line + val avgY = size.height - (avg / maxLen) * size.height * 0.85f + drawLine( + color = avgColor, + start = Offset(0f, avgY), + end = Offset(size.width, avgY), + strokeWidth = 2.dp.toPx() + ) + } + Spacer(Modifier.height(4.dp)) + Text( + "Last ${cycles.size} cycles ยท Average: ${avg.toInt()} days", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) +} diff --git a/app/src/main/java/com/hsdiary/ui/insights/CycleInsightsViewModel.kt b/app/src/main/java/com/hsdiary/ui/insights/CycleInsightsViewModel.kt new file mode 100644 index 0000000..76a4fdc --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/insights/CycleInsightsViewModel.kt @@ -0,0 +1,65 @@ +package com.hsdiary.ui.insights + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.hsdiary.data.db.entity.CycleRecordEntity +import com.hsdiary.data.db.entity.ProfileEntity +import com.hsdiary.data.model.ProfileType +import com.hsdiary.data.preferences.UserPreferences +import com.hsdiary.data.repository.CycleRepository +import com.hsdiary.data.repository.ProfileRepository +import com.hsdiary.domain.CyclePredictionEngine +import com.hsdiary.domain.model.CyclePrediction +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import java.time.LocalDate +import javax.inject.Inject + +data class CycleInsightsUiState( + val profile: ProfileEntity? = null, + val prediction: CyclePrediction? = null, + val recentCycles: List = emptyList(), + val isLoading: Boolean = true +) + +@HiltViewModel +class CycleInsightsViewModel @Inject constructor( + private val profileRepository: ProfileRepository, + private val cycleRepository: CycleRepository, + private val predictionEngine: CyclePredictionEngine, + private val userPreferences: UserPreferences +) : ViewModel() { + + private val _uiState = MutableStateFlow(CycleInsightsUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + init { + viewModelScope.launch { load() } + } + + private suspend fun load() { + val activeId = userPreferences.activeProfileId.first() + val profiles = profileRepository.getAllProfilesOnce() + val profile = profiles.find { it.id == activeId } ?: profiles.firstOrNull() ?: return + if (profile.profileType != ProfileType.FEMALE.name) { + _uiState.value = CycleInsightsUiState(profile = profile, isLoading = false) + return + } + cycleRepository.getCycleRecords(profile.id) + .onEach { records -> + val prediction = predictionEngine.buildPrediction( + records = records, + defaultCycleLength = profile.cycleLengthDefault, + today = LocalDate.now() + ) + _uiState.value = CycleInsightsUiState( + profile = profile, + prediction = prediction, + recentCycles = records.takeLast(12), + isLoading = false + ) + } + .launchIn(viewModelScope) + } +} diff --git a/app/src/main/java/com/hsdiary/ui/navigation/AppNavigation.kt b/app/src/main/java/com/hsdiary/ui/navigation/AppNavigation.kt new file mode 100644 index 0000000..9012c8a --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/navigation/AppNavigation.kt @@ -0,0 +1,60 @@ +package com.hsdiary.ui.navigation + +import androidx.compose.runtime.* +import androidx.compose.runtime.collectAsState +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import com.hsdiary.ui.calendar.CalendarScreen +import com.hsdiary.ui.daydetail.DayDetailScreen +import com.hsdiary.ui.insights.CycleInsightsScreen +import com.hsdiary.ui.onboarding.OnboardingScreen +import com.hsdiary.ui.onboarding.OnboardingViewModel +import com.hsdiary.ui.settings.SettingsScreen +import com.hsdiary.ui.trends.HealthTrendsScreen + +@Composable +fun AppNavigation() { + val navController = rememberNavController() + val onboardingVm: OnboardingViewModel = hiltViewModel() + val onboardingComplete by onboardingVm.onboardingComplete.collectAsState(initial = null) + + if (onboardingComplete == null) return // wait for prefs to load + + NavHost( + navController = navController, + startDestination = if (onboardingComplete == true) Screen.Calendar.route else Screen.Onboarding.route + ) { + composable(Screen.Onboarding.route) { + OnboardingScreen( + onComplete = { + navController.navigate(Screen.Calendar.route) { + popUpTo(Screen.Onboarding.route) { inclusive = true } + } + } + ) + } + composable(Screen.Calendar.route) { + CalendarScreen( + onDayClick = { date -> navController.navigate(Screen.DayDetail.createRoute(date)) }, + onInsightsClick = { navController.navigate(Screen.CycleInsights.route) }, + onTrendsClick = { navController.navigate(Screen.HealthTrends.route) }, + onSettingsClick = { navController.navigate(Screen.Settings.route) } + ) + } + composable(Screen.DayDetail.route) { backstack -> + val date = backstack.arguments?.getString("date") ?: return@composable + DayDetailScreen(date = date, onBack = { navController.popBackStack() }) + } + composable(Screen.CycleInsights.route) { + CycleInsightsScreen(onBack = { navController.popBackStack() }) + } + composable(Screen.HealthTrends.route) { + HealthTrendsScreen(onBack = { navController.popBackStack() }) + } + composable(Screen.Settings.route) { + SettingsScreen(onBack = { navController.popBackStack() }) + } + } +} diff --git a/app/src/main/java/com/hsdiary/ui/navigation/Screen.kt b/app/src/main/java/com/hsdiary/ui/navigation/Screen.kt new file mode 100644 index 0000000..53f2c9e --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/navigation/Screen.kt @@ -0,0 +1,12 @@ +package com.hsdiary.ui.navigation + +sealed class Screen(val route: String) { + object Onboarding : Screen("onboarding") + object Calendar : Screen("calendar") + object DayDetail : Screen("day_detail/{date}") { + fun createRoute(date: String) = "day_detail/$date" + } + object CycleInsights : Screen("cycle_insights") + object HealthTrends : Screen("health_trends") + object Settings : Screen("settings") +} diff --git a/app/src/main/java/com/hsdiary/ui/onboarding/OnboardingScreen.kt b/app/src/main/java/com/hsdiary/ui/onboarding/OnboardingScreen.kt new file mode 100644 index 0000000..8155842 --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/onboarding/OnboardingScreen.kt @@ -0,0 +1,165 @@ +package com.hsdiary.ui.onboarding + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import com.hsdiary.data.model.ProfileType +import com.hsdiary.ui.theme.AvatarColors + +@Composable +fun OnboardingScreen( + onComplete: () -> Unit, + viewModel: OnboardingViewModel = hiltViewModel() +) { + val state by viewModel.uiState.collectAsState() + + when (state.step) { + 0 -> WelcomeStep(onNext = { viewModel.nextStep() }) + 1 -> ProfileSetupStep( + title = "Create your profile", + name = state.profile1Name, + colorIndex = state.profile1ColorIndex, + profileType = state.profile1Type, + onNameChange = viewModel::updateProfile1Name, + onColorChange = viewModel::updateProfile1Color, + onTypeChange = viewModel::updateProfile1Type, + onNext = { viewModel.nextStep() }, + canSkip = false + ) + 2 -> ProfileSetupStep( + title = "Add a second profile", + subtitle = "Optional โ€” can be added later in Settings", + name = state.profile2Name, + colorIndex = state.profile2ColorIndex, + profileType = state.profile2Type, + onNameChange = viewModel::updateProfile2Name, + onColorChange = viewModel::updateProfile2Color, + onTypeChange = viewModel::updateProfile2Type, + onNext = { viewModel.completeOnboarding(onComplete) }, + canSkip = true, + onSkip = { viewModel.completeOnboarding(onComplete) }, + isLoading = state.isLoading + ) + } +} + +@Composable +private fun WelcomeStep(onNext: () -> Unit) { + Column( + modifier = Modifier.fillMaxSize().padding(32.dp), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text("๐Ÿฉบ", style = MaterialTheme.typography.displayLarge) + Spacer(Modifier.height(24.dp)) + Text( + text = "H&S Diary", + style = MaterialTheme.typography.headlineLarge, + fontWeight = FontWeight.Bold + ) + Spacer(Modifier.height(12.dp)) + Text( + text = "Your private health & cycle tracker.\nAll data stays on your device.", + style = MaterialTheme.typography.bodyLarge, + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + Spacer(Modifier.height(48.dp)) + Button(onClick = onNext, modifier = Modifier.fillMaxWidth()) { + Text("Get Started") + } + } +} + +@Composable +private fun ProfileSetupStep( + title: String, + subtitle: String? = null, + name: String, + colorIndex: Int, + profileType: ProfileType, + onNameChange: (String) -> Unit, + onColorChange: (Int) -> Unit, + onTypeChange: (ProfileType) -> Unit, + onNext: () -> Unit, + canSkip: Boolean, + onSkip: (() -> Unit)? = null, + isLoading: Boolean = false +) { + Column( + modifier = Modifier.fillMaxSize().padding(horizontal = 24.dp, vertical = 48.dp), + verticalArrangement = Arrangement.spacedBy(20.dp) + ) { + Text(title, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold) + if (subtitle != null) { + Text(subtitle, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) + } + + OutlinedTextField( + value = name, + onValueChange = { if (it.length <= 32) onNameChange(it) }, + label = { Text("Name") }, + singleLine = true, + modifier = Modifier.fillMaxWidth() + ) + + // Profile type selector + Text("Profile type", style = MaterialTheme.typography.labelLarge) + Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { + ProfileType.values().forEach { type -> + FilterChip( + selected = profileType == type, + onClick = { onTypeChange(type) }, + label = { Text(if (type == ProfileType.FEMALE) "Female" else "Male") } + ) + } + } + + // Color selector + Text("Avatar color", style = MaterialTheme.typography.labelLarge) + Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) { + AvatarColors.forEachIndexed { idx, color -> + Box( + modifier = Modifier + .size(36.dp) + .clip(CircleShape) + .background(color) + .then( + if (idx == colorIndex) Modifier.border(3.dp, MaterialTheme.colorScheme.onSurface, CircleShape) + else Modifier + ) + .clickable { onColorChange(idx) } + ) + } + } + + Spacer(Modifier.weight(1f)) + + Button( + onClick = onNext, + enabled = !isLoading && (name.isNotBlank() || canSkip), + modifier = Modifier.fillMaxWidth() + ) { + if (isLoading) CircularProgressIndicator(modifier = Modifier.size(18.dp), strokeWidth = 2.dp) + else Text(if (canSkip && name.isBlank()) "Skip" else "Continue") + } + if (canSkip && name.isNotBlank()) { + TextButton(onClick = { onSkip?.invoke() }, modifier = Modifier.fillMaxWidth()) { + Text("Skip for now") + } + } + } +} diff --git a/app/src/main/java/com/hsdiary/ui/onboarding/OnboardingViewModel.kt b/app/src/main/java/com/hsdiary/ui/onboarding/OnboardingViewModel.kt new file mode 100644 index 0000000..8121f3f --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/onboarding/OnboardingViewModel.kt @@ -0,0 +1,77 @@ +package com.hsdiary.ui.onboarding + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.hsdiary.data.db.entity.ProfileEntity +import com.hsdiary.data.model.ProfileType +import com.hsdiary.data.preferences.UserPreferences +import com.hsdiary.data.repository.ProfileRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +data class OnboardingUiState( + val step: Int = 0, // 0=welcome, 1=profile1, 2=profile2_prompt, 3=complete + val profile1Name: String = "", + val profile1ColorIndex: Int = 0, + val profile1Type: ProfileType = ProfileType.FEMALE, + val profile2Name: String = "", + val profile2ColorIndex: Int = 1, + val profile2Type: ProfileType = ProfileType.MALE, + val isLoading: Boolean = false +) + +@HiltViewModel +class OnboardingViewModel @Inject constructor( + private val profileRepository: ProfileRepository, + private val userPreferences: UserPreferences +) : ViewModel() { + + val onboardingComplete = userPreferences.onboardingComplete + + private val _uiState = MutableStateFlow(OnboardingUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + fun updateProfile1Name(name: String) { _uiState.value = _uiState.value.copy(profile1Name = name) } + fun updateProfile1Color(idx: Int) { _uiState.value = _uiState.value.copy(profile1ColorIndex = idx) } + fun updateProfile1Type(type: ProfileType) { _uiState.value = _uiState.value.copy(profile1Type = type) } + fun updateProfile2Name(name: String) { _uiState.value = _uiState.value.copy(profile2Name = name) } + fun updateProfile2Color(idx: Int) { _uiState.value = _uiState.value.copy(profile2ColorIndex = idx) } + fun updateProfile2Type(type: ProfileType) { _uiState.value = _uiState.value.copy(profile2Type = type) } + + fun nextStep() { _uiState.value = _uiState.value.copy(step = _uiState.value.step + 1) } + + fun completeOnboarding(onDone: () -> Unit) { + viewModelScope.launch { + _uiState.value = _uiState.value.copy(isLoading = true) + val state = _uiState.value + val colorHexes = listOf( + "#E91E63","#9C27B0","#2196F3","#009688", + "#4CAF50","#FF9800","#FF4081","#7C4DFF" + ) + val id1 = profileRepository.insertProfile( + ProfileEntity( + name = state.profile1Name.trim().ifEmpty { "Profile 1" }, + avatarColor = colorHexes[state.profile1ColorIndex], + profileType = state.profile1Type.name + ) + ) + userPreferences.setActiveProfileId(id1) + + if (state.profile2Name.isNotBlank()) { + profileRepository.insertProfile( + ProfileEntity( + name = state.profile2Name.trim(), + avatarColor = colorHexes[state.profile2ColorIndex], + profileType = state.profile2Type.name + ) + ) + } + userPreferences.setOnboardingComplete(true) + onDone() + } + } +} diff --git a/app/src/main/java/com/hsdiary/ui/settings/SettingsScreen.kt b/app/src/main/java/com/hsdiary/ui/settings/SettingsScreen.kt new file mode 100644 index 0000000..2697c35 --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/settings/SettingsScreen.kt @@ -0,0 +1,242 @@ +package com.hsdiary.ui.settings + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import com.hsdiary.data.db.entity.ProfileEntity +import com.hsdiary.ui.calendar.parseColor +import com.hsdiary.ui.theme.AvatarColors + +private val colorHexes = listOf( + "#E91E63","#9C27B0","#2196F3","#009688", + "#4CAF50","#FF9800","#FF4081","#7C4DFF" +) + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SettingsScreen( + onBack: () -> Unit, + viewModel: SettingsViewModel = hiltViewModel() +) { + val state by viewModel.uiState.collectAsState() + var clearProfileTarget by remember { mutableStateOf(null) } + var showClearAll by remember { mutableStateOf(false) } + + Scaffold( + topBar = { + TopAppBar( + title = { Text("Settings") }, + navigationIcon = { + IconButton(onClick = onBack) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, "Back") + } + } + ) + } + ) { padding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(padding) + .verticalScroll(rememberScrollState()) + ) { + // App settings + SettingsSection("App") { + // First day of week + ListItem( + headlineContent = { Text("First day of week") }, + trailingContent = { + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + FilterChip( + selected = state.firstDayOfWeek == 1, + onClick = { viewModel.setFirstDayOfWeek(1) }, + label = { Text("Sunday") } + ) + FilterChip( + selected = state.firstDayOfWeek == 2, + onClick = { viewModel.setFirstDayOfWeek(2) }, + label = { Text("Monday") } + ) + } + } + ) + HorizontalDivider() + // Theme + ListItem( + headlineContent = { Text("App theme") }, + trailingContent = { + Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) { + listOf("Light", "Dark", "System").forEach { theme -> + val key = theme.uppercase() + FilterChip( + selected = state.appTheme == key, + onClick = { viewModel.setAppTheme(key) }, + label = { Text(theme) } + ) + } + } + } + ) + } + + // Profile settings + state.profiles.forEach { profile -> + SettingsSection("Profile: ${profile.name}") { + ProfileSettingsCard( + profile = profile, + onNameChange = { viewModel.updateProfileName(profile.id, it) }, + onColorChange = { viewModel.updateProfileColor(profile.id, it) } + ) + HorizontalDivider() + ListItem( + headlineContent = { Text("Clear profile data", color = MaterialTheme.colorScheme.error) }, + supportingContent = { Text("Removes all logs for this profile") }, + modifier = Modifier.clickable { clearProfileTarget = profile.id } + ) + } + } + + // Data management + SettingsSection("Data") { + ListItem( + headlineContent = { Text("Clear all data", color = MaterialTheme.colorScheme.error) }, + supportingContent = { Text("Removes all profiles and data โ€” cannot be undone") }, + modifier = Modifier.clickable { showClearAll = true } + ) + } + + Spacer(Modifier.height(32.dp)) + Text( + "H&S Diary ยท All data stored locally on this device.", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp) + ) + } + } + + // Confirm clear profile + clearProfileTarget?.let { profileId -> + val profile = state.profiles.find { it.id == profileId } + AlertDialog( + onDismissRequest = { clearProfileTarget = null }, + title = { Text("Clear data?") }, + text = { Text("This will remove all logs for ${profile?.name}. This cannot be undone.") }, + confirmButton = { + TextButton(onClick = { + viewModel.clearProfileData(profileId) + clearProfileTarget = null + }, colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colorScheme.error)) { + Text("Clear") + } + }, + dismissButton = { + TextButton(onClick = { clearProfileTarget = null }) { Text("Cancel") } + } + ) + } + + // Confirm clear all + if (showClearAll) { + AlertDialog( + onDismissRequest = { showClearAll = false }, + title = { Text("Clear all data?") }, + text = { Text("This will remove all profiles, logs, and reset the app. This CANNOT be undone.") }, + confirmButton = { + TextButton( + onClick = { viewModel.clearAllData(); showClearAll = false }, + colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colorScheme.error) + ) { Text("Clear Everything") } + }, + dismissButton = { + TextButton(onClick = { showClearAll = false }) { Text("Cancel") } + } + ) + } +} + +@Composable +private fun SettingsSection(title: String, content: @Composable ColumnScope.() -> Unit) { + Column(modifier = Modifier.fillMaxWidth().padding(top = 8.dp)) { + Text( + title, + style = MaterialTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp) + ) + Card( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface) + ) { + Column { content() } + } + } +} + +@Composable +private fun ProfileSettingsCard( + profile: ProfileEntity, + onNameChange: (String) -> Unit, + onColorChange: (String) -> Unit +) { + var editingName by remember(profile.id) { mutableStateOf(profile.name) } + var nameEditMode by remember { mutableStateOf(false) } + + Column(modifier = Modifier.padding(16.dp)) { + // Name + if (nameEditMode) { + OutlinedTextField( + value = editingName, + onValueChange = { if (it.length <= 32) editingName = it }, + label = { Text("Name") }, + singleLine = true, + modifier = Modifier.fillMaxWidth(), + trailingIcon = { + TextButton(onClick = { + onNameChange(editingName) + nameEditMode = false + }) { Text("Save") } + } + ) + } else { + ListItem( + headlineContent = { Text(profile.name) }, + supportingContent = { Text("Tap to edit name") }, + modifier = Modifier.clickable { nameEditMode = true } + ) + } + + Spacer(Modifier.height(8.dp)) + Text("Avatar color", style = MaterialTheme.typography.labelMedium) + Spacer(Modifier.height(8.dp)) + Row(horizontalArrangement = Arrangement.spacedBy(10.dp), modifier = Modifier.padding(horizontal = 4.dp)) { + colorHexes.forEachIndexed { idx, hex -> + val color = parseColor(hex) + val isSelected = profile.avatarColor == hex + Box( + modifier = Modifier + .size(32.dp) + .clip(CircleShape) + .background(color) + .then(if (isSelected) Modifier.border(3.dp, MaterialTheme.colorScheme.onSurface, CircleShape) else Modifier) + .clickable { onColorChange(hex) } + ) + } + } + } +} diff --git a/app/src/main/java/com/hsdiary/ui/settings/SettingsViewModel.kt b/app/src/main/java/com/hsdiary/ui/settings/SettingsViewModel.kt new file mode 100644 index 0000000..4d86a27 --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/settings/SettingsViewModel.kt @@ -0,0 +1,95 @@ +package com.hsdiary.ui.settings + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.hsdiary.data.db.entity.ProfileEntity +import com.hsdiary.data.model.ProfileType +import com.hsdiary.data.preferences.UserPreferences +import com.hsdiary.data.repository.CycleRepository +import com.hsdiary.data.repository.DayLogRepository +import com.hsdiary.data.repository.IntimacyRepository +import com.hsdiary.data.repository.ProfileRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import javax.inject.Inject + +data class SettingsUiState( + val profiles: List = emptyList(), + val activeProfileId: Long? = null, + val firstDayOfWeek: Int = 1, + val appTheme: String = "SYSTEM", + val isLoading: Boolean = false, + val confirmClearProfileId: Long? = null, + val confirmClearAll: Boolean = false +) + +@HiltViewModel +class SettingsViewModel @Inject constructor( + private val profileRepository: ProfileRepository, + private val dayLogRepository: DayLogRepository, + private val cycleRepository: CycleRepository, + private val intimacyRepository: IntimacyRepository, + private val userPreferences: UserPreferences +) : ViewModel() { + + val uiState: StateFlow = combine( + profileRepository.getAllProfiles(), + userPreferences.activeProfileId, + userPreferences.firstDayOfWeek, + userPreferences.appTheme + ) { profiles, activeId, fdow, theme -> + SettingsUiState(profiles = profiles, activeProfileId = activeId, firstDayOfWeek = fdow, appTheme = theme) + }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), SettingsUiState()) + + fun setFirstDayOfWeek(day: Int) { + viewModelScope.launch { userPreferences.setFirstDayOfWeek(day) } + } + + fun setAppTheme(theme: String) { + viewModelScope.launch { userPreferences.setAppTheme(theme) } + } + + fun updateProfileName(profileId: Long, name: String) { + viewModelScope.launch { + val profile = profileRepository.getProfileById(profileId) ?: return@launch + profileRepository.updateProfile(profile.copy(name = name.trim())) + } + } + + fun updateProfileColor(profileId: Long, colorHex: String) { + viewModelScope.launch { + val profile = profileRepository.getProfileById(profileId) ?: return@launch + profileRepository.updateProfile(profile.copy(avatarColor = colorHex)) + } + } + + fun updateReproductiveStatus(profileId: Long, statusJson: String) { + viewModelScope.launch { + val profile = profileRepository.getProfileById(profileId) ?: return@launch + profileRepository.updateProfile(profile.copy(reproductiveStatus = statusJson)) + } + } + + fun clearProfileData(profileId: Long) { + viewModelScope.launch { + dayLogRepository.deleteAllForProfile(profileId) + cycleRepository.deleteAllForProfile(profileId) + intimacyRepository.deleteAllForProfile(profileId) + } + } + + fun clearAllData() { + viewModelScope.launch { + val profiles = profileRepository.getAllProfilesOnce() + profiles.forEach { p -> + dayLogRepository.deleteAllForProfile(p.id) + cycleRepository.deleteAllForProfile(p.id) + intimacyRepository.deleteAllForProfile(p.id) + profileRepository.deleteProfile(p) + } + userPreferences.setOnboardingComplete(false) + userPreferences.setActiveProfileId(0L) + } + } +} diff --git a/app/src/main/java/com/hsdiary/ui/theme/Color.kt b/app/src/main/java/com/hsdiary/ui/theme/Color.kt new file mode 100644 index 0000000..89d7eae --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/theme/Color.kt @@ -0,0 +1,31 @@ +package com.hsdiary.ui.theme + +import androidx.compose.ui.graphics.Color + +// Material theme seeds +val PrimaryPink = Color(0xFFE91E63) +val PrimaryPinkDark = Color(0xFFC2185B) +val OnPrimary = Color(0xFFFFFFFF) + +// Cycle phase colors +val PeriodColor = Color(0xFFB71C1C) +val PeriodPredictedColor = Color(0xFFEF9A9A) +val FertileColor = Color(0xFF00796B) +val FertilePredictedColor = Color(0xFF80CBC4) +val OvulationColor = Color(0xFF00897B) +val LutealColor = Color(0xFFF57F17) +val FollicularColor = Color(0xFFE0E0E0) + +// Avatar palette (8 swatches) +val AvatarColors = listOf( + Color(0xFFE91E63), // Rose + Color(0xFF9C27B0), // Purple + Color(0xFF2196F3), // Blue + Color(0xFF009688), // Teal + Color(0xFF4CAF50), // Green + Color(0xFFFF9800), // Orange + Color(0xFFFF4081), // Pink accent + Color(0xFF7C4DFF) // Violet +) + +val AvatarColorLabels = listOf("Rose", "Purple", "Blue", "Teal", "Green", "Orange", "Pink", "Violet") diff --git a/app/src/main/java/com/hsdiary/ui/theme/Theme.kt b/app/src/main/java/com/hsdiary/ui/theme/Theme.kt new file mode 100644 index 0000000..89465d6 --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/theme/Theme.kt @@ -0,0 +1,56 @@ +package com.hsdiary.ui.theme + +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext + +private val LightColors = lightColorScheme( + primary = PrimaryPink, + onPrimary = OnPrimary, + primaryContainer = Color(0xFFFCE4EC), + onPrimaryContainer = Color(0xFF880E4F), + secondary = Color(0xFF009688), + onSecondary = OnPrimary, + secondaryContainer = Color(0xFFE0F2F1), + onSecondaryContainer = Color(0xFF004D40), + surface = Color(0xFFFFFBFE), + onSurface = Color(0xFF1C1B1F), + surfaceVariant = Color(0xFFF5F5F5), + onSurfaceVariant = Color(0xFF49454F), + outline = Color(0xFF79747E) +) + +private val DarkColors = darkColorScheme( + primary = Color(0xFFF48FB1), + onPrimary = Color(0xFF880E4F), + primaryContainer = Color(0xFFAD1457), + onPrimaryContainer = Color(0xFFFCE4EC), + secondary = Color(0xFF80CBC4), + onSecondary = Color(0xFF004D40), + surface = Color(0xFF1C1B1F), + onSurface = Color(0xFFE6E1E5) +) + +@Composable +fun HSDiaryTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + content: @Composable () -> Unit +) { + val colorScheme = when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + darkTheme -> DarkColors + else -> LightColors + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} diff --git a/app/src/main/java/com/hsdiary/ui/theme/Type.kt b/app/src/main/java/com/hsdiary/ui/theme/Type.kt new file mode 100644 index 0000000..4a937c3 --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/theme/Type.kt @@ -0,0 +1,15 @@ +package com.hsdiary.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +val Typography = Typography( + bodyLarge = TextStyle(fontWeight = FontWeight.Normal, fontSize = 16.sp, lineHeight = 24.sp), + bodyMedium = TextStyle(fontWeight = FontWeight.Normal, fontSize = 14.sp, lineHeight = 20.sp), + bodySmall = TextStyle(fontWeight = FontWeight.Normal, fontSize = 12.sp, lineHeight = 16.sp), + titleLarge = TextStyle(fontWeight = FontWeight.SemiBold, fontSize = 22.sp, lineHeight = 28.sp), + titleMedium = TextStyle(fontWeight = FontWeight.SemiBold, fontSize = 16.sp, lineHeight = 24.sp), + labelSmall = TextStyle(fontWeight = FontWeight.Medium, fontSize = 11.sp, lineHeight = 16.sp) +) diff --git a/app/src/main/java/com/hsdiary/ui/trends/HealthTrendsScreen.kt b/app/src/main/java/com/hsdiary/ui/trends/HealthTrendsScreen.kt new file mode 100644 index 0000000..ef556cb --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/trends/HealthTrendsScreen.kt @@ -0,0 +1,176 @@ +package com.hsdiary.ui.trends + +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun HealthTrendsScreen( + onBack: () -> Unit, + viewModel: HealthTrendsViewModel = hiltViewModel() +) { + val state by viewModel.uiState.collectAsState() + + Scaffold( + topBar = { + TopAppBar( + title = { Text("Health Trends") }, + navigationIcon = { + IconButton(onClick = onBack) { + Icon(Icons.AutoMirrored.Filled.ArrowBack, "Back") + } + } + ) + } + ) { padding -> + if (state.isLoading) { + Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + CircularProgressIndicator() + } + return@Scaffold + } + + LazyColumn( + modifier = Modifier.fillMaxSize().padding(padding), + contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + // Range selector + item { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(6.dp) + ) { + TrendsRange.values().forEach { range -> + FilterChip( + selected = state.range == range, + onClick = { viewModel.setRange(range) }, + label = { + Text(when (range) { + TrendsRange.DAYS_30 -> "30d" + TrendsRange.MONTHS_3 -> "3m" + TrendsRange.MONTHS_6 -> "6m" + TrendsRange.ALL -> "All" + }, style = MaterialTheme.typography.labelSmall) + } + ) + } + } + } + + // Summary header + if (state.conditionFrequencies.isEmpty()) { + item { + Box( + Modifier.fillMaxWidth().padding(vertical = 48.dp), + contentAlignment = Alignment.Center + ) { + Text( + "No conditions logged in this range.", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + } else { + item { + Text( + "Logged this period", + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.SemiBold + ) + } + items(state.conditionFrequencies) { freq -> + ConditionFrequencyCard( + frequency = freq, + isSelected = state.selectedCondition?.conditionKey == freq.definition.conditionKey, + onClick = { + viewModel.selectCondition( + if (state.selectedCondition?.conditionKey == freq.definition.conditionKey) null + else freq.definition + ) + } + ) + } + } + } + } +} + +@Composable +private fun ConditionFrequencyCard( + frequency: ConditionFrequency, + isSelected: Boolean, + onClick: () -> Unit +) { + val barColor = MaterialTheme.colorScheme.primary + + ElevatedCard( + modifier = Modifier.fillMaxWidth().clickable(onClick = onClick) + ) { + Column(modifier = Modifier.padding(16.dp)) { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Column(modifier = Modifier.weight(1f)) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text(frequency.definition.displayName, style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.Medium) + if (frequency.isRecurring) { + Badge(containerColor = MaterialTheme.colorScheme.tertiaryContainer) { + Text("Recurring", style = MaterialTheme.typography.labelSmall) + } + } + } + Text( + "${frequency.count} times ยท avg rating ${"%.1f".format(frequency.avgRating)}/5", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + Text( + "ร—${frequency.count}", + style = MaterialTheme.typography.titleLarge, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.primary + ) + } + + if (isSelected && frequency.weeklyData.isNotEmpty()) { + Spacer(Modifier.height(12.dp)) + Text("Weekly occurrences", style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant) + Spacer(Modifier.height(4.dp)) + val maxCount = (frequency.weeklyData.maxOrNull() ?: 1).toFloat().coerceAtLeast(1f) + Canvas(modifier = Modifier.fillMaxWidth().height(60.dp)) { + val barW = size.width / (frequency.weeklyData.size * 1.5f) + val gap = barW * 0.5f + frequency.weeklyData.forEachIndexed { i, count -> + val h = (count / maxCount) * size.height * 0.9f + drawRect( + color = barColor, + topLeft = Offset(i * (barW + gap), size.height - h), + size = Size(barW, h) + ) + } + } + } + } + } +} diff --git a/app/src/main/java/com/hsdiary/ui/trends/HealthTrendsViewModel.kt b/app/src/main/java/com/hsdiary/ui/trends/HealthTrendsViewModel.kt new file mode 100644 index 0000000..cef476a --- /dev/null +++ b/app/src/main/java/com/hsdiary/ui/trends/HealthTrendsViewModel.kt @@ -0,0 +1,130 @@ +package com.hsdiary.ui.trends + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.hsdiary.data.db.entity.ConditionDefinitionEntity +import com.hsdiary.data.db.entity.ConditionEntryEntity +import com.hsdiary.data.db.entity.DayLogEntity +import com.hsdiary.data.db.entity.ProfileEntity +import com.hsdiary.data.model.ProfileType +import com.hsdiary.data.preferences.UserPreferences +import com.hsdiary.data.repository.CycleRepository +import com.hsdiary.data.repository.DayLogRepository +import com.hsdiary.data.repository.ProfileRepository +import com.hsdiary.domain.CyclePredictionEngine +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.launch +import java.time.LocalDate +import javax.inject.Inject + +enum class TrendsRange { DAYS_30, MONTHS_3, MONTHS_6, ALL } + +data class ConditionFrequency( + val definition: ConditionDefinitionEntity, + val count: Int, + val isRecurring: Boolean, + val avgRating: Float, + val weeklyData: List +) + +data class HealthTrendsUiState( + val profile: ProfileEntity? = null, + val range: TrendsRange = TrendsRange.DAYS_30, + val conditionFrequencies: List = emptyList(), + val selectedCondition: ConditionDefinitionEntity? = null, + val isLoading: Boolean = true, + val isFemale: Boolean = false +) + +@HiltViewModel +class HealthTrendsViewModel @Inject constructor( + private val profileRepository: ProfileRepository, + private val dayLogRepository: DayLogRepository, + private val userPreferences: UserPreferences +) : ViewModel() { + + private val _range = MutableStateFlow(TrendsRange.DAYS_30) + private val _selectedCondition = MutableStateFlow(null) + private val _uiState = MutableStateFlow(HealthTrendsUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + + init { + viewModelScope.launch { load() } + } + + private suspend fun load() { + val activeId = userPreferences.activeProfileId.first() + val profiles = profileRepository.getAllProfilesOnce() + val profile = profiles.find { it.id == activeId } ?: profiles.firstOrNull() ?: return + val isFemale = profile.profileType == ProfileType.FEMALE.name + val allDefs = dayLogRepository.getAllDefinitions() + .filter { it.profileVisibility == "ALL" || (isFemale && it.profileVisibility == "FEMALE_ONLY") } + + _range.combine(_selectedCondition) { range, sel -> range to sel } + .onEach { (range, sel) -> + val today = LocalDate.now() + val startDate = when (range) { + TrendsRange.DAYS_30 -> today.minusDays(29) + TrendsRange.MONTHS_3 -> today.minusMonths(3) + TrendsRange.MONTHS_6 -> today.minusMonths(6) + TrendsRange.ALL -> today.minusYears(5) + } + + val entries = dayLogRepository.getConditionsInRange( + profile.id, startDate.toString(), today.toString() + ) + val dayLogs = dayLogRepository.getDayLogsInRangeOnce( + profile.id, startDate.toString(), today.toString() + ) + val dayLogMap = dayLogs.associateBy { it.id } + + val grouped = entries.groupBy { it.conditionKey } + val frequencies = allDefs.mapNotNull { def -> + val entriesForKey = grouped[def.conditionKey] ?: return@mapNotNull null + val weeklyData = buildWeeklyData(entriesForKey, dayLogMap, startDate, today) + ConditionFrequency( + definition = def, + count = entriesForKey.size, + isRecurring = entriesForKey.size >= 3, + avgRating = entriesForKey.map { it.rating }.average().toFloat(), + weeklyData = weeklyData + ) + }.sortedByDescending { it.count } + + _uiState.value = HealthTrendsUiState( + profile = profile, + range = range, + conditionFrequencies = frequencies, + selectedCondition = sel, + isLoading = false, + isFemale = isFemale + ) + } + .launchIn(viewModelScope) + } + + private fun buildWeeklyData( + entries: List, + dayLogMap: Map, + startDate: LocalDate, + today: LocalDate + ): List { + val weeks = mutableListOf() + var weekStart = startDate + while (!weekStart.isAfter(today)) { + val weekEnd = weekStart.plusDays(6) + val count = entries.count { entry -> + val log = dayLogMap[entry.dayLogId] ?: return@count false + val date = LocalDate.parse(log.date) + !date.isBefore(weekStart) && !date.isAfter(weekEnd) + } + weeks.add(count) + weekStart = weekStart.plusWeeks(1) + } + return weeks + } + + fun setRange(range: TrendsRange) { _range.value = range } + fun selectCondition(def: ConditionDefinitionEntity?) { _selectedCondition.value = def } +} diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..dd3f185 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,8 @@ + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..6bf73b4 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,10 @@ + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..6b78462 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..6b78462 --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..fd91a92 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + H&S Diary + diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..9ace507 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,4 @@ + + +