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 <whitlocktech@gmail.com>
This commit is contained in:
2026-05-22 17:21:30 -05:00
commit b3bd69ab26
138 changed files with 8150 additions and 0 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
<EFBFBD>ng6z6wm4ijfn5auy4sgagtfpdeL<><4C><EFBFBD>u<EFBFBD>> b8<62><38>

View File

@@ -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 <b>androidx</b>
*/
public AndroidxLibraryAccessors getAndroidx() {
return laccForAndroidxLibraryAccessors;
}
/**
* Group of libraries at <b>compose</b>
*/
public ComposeLibraryAccessors getCompose() {
return laccForComposeLibraryAccessors;
}
/**
* Group of libraries at <b>datastore</b>
*/
public DatastoreLibraryAccessors getDatastore() {
return laccForDatastoreLibraryAccessors;
}
/**
* Group of libraries at <b>hilt</b>
*/
public HiltLibraryAccessors getHilt() {
return laccForHiltLibraryAccessors;
}
/**
* Group of libraries at <b>kotlinx</b>
*/
public KotlinxLibraryAccessors getKotlinx() {
return laccForKotlinxLibraryAccessors;
}
/**
* Group of libraries at <b>lifecycle</b>
*/
public LifecycleLibraryAccessors getLifecycle() {
return laccForLifecycleLibraryAccessors;
}
/**
* Group of libraries at <b>navigation</b>
*/
public NavigationLibraryAccessors getNavigation() {
return laccForNavigationLibraryAccessors;
}
/**
* Group of libraries at <b>room</b>
*/
public RoomLibraryAccessors getRoom() {
return laccForRoomLibraryAccessors;
}
/**
* Group of versions at <b>versions</b>
*/
public VersionAccessors getVersions() {
return vaccForVersionAccessors;
}
/**
* Group of bundles at <b>bundles</b>
*/
public BundleAccessors getBundles() {
return baccForBundleAccessors;
}
/**
* Group of plugins at <b>plugins</b>
*/
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 <b>androidx.activity</b>
*/
public AndroidxActivityLibraryAccessors getActivity() {
return laccForAndroidxActivityLibraryAccessors;
}
/**
* Group of libraries at <b>androidx.core</b>
*/
public AndroidxCoreLibraryAccessors getCore() {
return laccForAndroidxCoreLibraryAccessors;
}
}
public static class AndroidxActivityLibraryAccessors extends SubDependencyFactory {
public AndroidxActivityLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); }
/**
* Dependency provider for <b>compose</b> with <b>androidx.activity:activity-compose</b> coordinates and
* with version reference <b>activityCompose</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> getCompose() {
return create("androidx.activity.compose");
}
}
public static class AndroidxCoreLibraryAccessors extends SubDependencyFactory {
public AndroidxCoreLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); }
/**
* Dependency provider for <b>ktx</b> with <b>androidx.core:core-ktx</b> coordinates and
* with version reference <b>coreKtx</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> 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 <b>bom</b> with <b>androidx.compose:compose-bom</b> coordinates and
* with version reference <b>composeBom</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> getBom() {
return create("compose.bom");
}
/**
* Dependency provider for <b>material3</b> with <b>androidx.compose.material3:material3</b> coordinates and
* with <b>no version specified</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> getMaterial3() {
return create("compose.material3");
}
/**
* Group of libraries at <b>compose.material</b>
*/
public ComposeMaterialLibraryAccessors getMaterial() {
return laccForComposeMaterialLibraryAccessors;
}
/**
* Group of libraries at <b>compose.ui</b>
*/
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 <b>compose.material.icons</b>
*/
public ComposeMaterialIconsLibraryAccessors getIcons() {
return laccForComposeMaterialIconsLibraryAccessors;
}
}
public static class ComposeMaterialIconsLibraryAccessors extends SubDependencyFactory {
public ComposeMaterialIconsLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); }
/**
* Dependency provider for <b>extended</b> with <b>androidx.compose.material:material-icons-extended</b> coordinates and
* with <b>no version specified</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> 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 <b>ui</b> with <b>androidx.compose.ui:ui</b> coordinates and
* with <b>no version specified</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> asProvider() {
return create("compose.ui");
}
/**
* Dependency provider for <b>graphics</b> with <b>androidx.compose.ui:ui-graphics</b> coordinates and
* with <b>no version specified</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> getGraphics() {
return create("compose.ui.graphics");
}
/**
* Group of libraries at <b>compose.ui.tooling</b>
*/
public ComposeUiToolingLibraryAccessors getTooling() {
return laccForComposeUiToolingLibraryAccessors;
}
}
public static class ComposeUiToolingLibraryAccessors extends SubDependencyFactory implements DependencyNotationSupplier {
public ComposeUiToolingLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); }
/**
* Dependency provider for <b>tooling</b> with <b>androidx.compose.ui:ui-tooling</b> coordinates and
* with <b>no version specified</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> asProvider() {
return create("compose.ui.tooling");
}
/**
* Dependency provider for <b>preview</b> with <b>androidx.compose.ui:ui-tooling-preview</b> coordinates and
* with <b>no version specified</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> getPreview() {
return create("compose.ui.tooling.preview");
}
}
public static class DatastoreLibraryAccessors extends SubDependencyFactory {
public DatastoreLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); }
/**
* Dependency provider for <b>preferences</b> with <b>androidx.datastore:datastore-preferences</b> coordinates and
* with version reference <b>datastore</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> 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 <b>android</b> with <b>com.google.dagger:hilt-android</b> coordinates and
* with version reference <b>hilt</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> getAndroid() {
return create("hilt.android");
}
/**
* Dependency provider for <b>compiler</b> with <b>com.google.dagger:hilt-android-compiler</b> coordinates and
* with version reference <b>hilt</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> getCompiler() {
return create("hilt.compiler");
}
/**
* Group of libraries at <b>hilt.navigation</b>
*/
public HiltNavigationLibraryAccessors getNavigation() {
return laccForHiltNavigationLibraryAccessors;
}
}
public static class HiltNavigationLibraryAccessors extends SubDependencyFactory {
public HiltNavigationLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); }
/**
* Dependency provider for <b>compose</b> with <b>androidx.hilt:hilt-navigation-compose</b> coordinates and
* with version reference <b>hiltNavigationCompose</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> 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 <b>kotlinx.coroutines</b>
*/
public KotlinxCoroutinesLibraryAccessors getCoroutines() {
return laccForKotlinxCoroutinesLibraryAccessors;
}
/**
* Group of libraries at <b>kotlinx.serialization</b>
*/
public KotlinxSerializationLibraryAccessors getSerialization() {
return laccForKotlinxSerializationLibraryAccessors;
}
}
public static class KotlinxCoroutinesLibraryAccessors extends SubDependencyFactory {
public KotlinxCoroutinesLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); }
/**
* Dependency provider for <b>android</b> with <b>org.jetbrains.kotlinx:kotlinx-coroutines-android</b> coordinates and
* with version reference <b>coroutines</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> getAndroid() {
return create("kotlinx.coroutines.android");
}
}
public static class KotlinxSerializationLibraryAccessors extends SubDependencyFactory {
public KotlinxSerializationLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); }
/**
* Dependency provider for <b>json</b> with <b>org.jetbrains.kotlinx:kotlinx-serialization-json</b> coordinates and
* with version reference <b>serialization</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> 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 <b>lifecycle.runtime</b>
*/
public LifecycleRuntimeLibraryAccessors getRuntime() {
return laccForLifecycleRuntimeLibraryAccessors;
}
/**
* Group of libraries at <b>lifecycle.viewmodel</b>
*/
public LifecycleViewmodelLibraryAccessors getViewmodel() {
return laccForLifecycleViewmodelLibraryAccessors;
}
}
public static class LifecycleRuntimeLibraryAccessors extends SubDependencyFactory {
public LifecycleRuntimeLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); }
/**
* Dependency provider for <b>compose</b> with <b>androidx.lifecycle:lifecycle-runtime-compose</b> coordinates and
* with version reference <b>lifecycle</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> getCompose() {
return create("lifecycle.runtime.compose");
}
/**
* Dependency provider for <b>ktx</b> with <b>androidx.lifecycle:lifecycle-runtime-ktx</b> coordinates and
* with version reference <b>lifecycle</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> getKtx() {
return create("lifecycle.runtime.ktx");
}
}
public static class LifecycleViewmodelLibraryAccessors extends SubDependencyFactory {
public LifecycleViewmodelLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); }
/**
* Dependency provider for <b>compose</b> with <b>androidx.lifecycle:lifecycle-viewmodel-compose</b> coordinates and
* with version reference <b>lifecycle</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> getCompose() {
return create("lifecycle.viewmodel.compose");
}
}
public static class NavigationLibraryAccessors extends SubDependencyFactory {
public NavigationLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); }
/**
* Dependency provider for <b>compose</b> with <b>androidx.navigation:navigation-compose</b> coordinates and
* with version reference <b>navigationCompose</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> getCompose() {
return create("navigation.compose");
}
}
public static class RoomLibraryAccessors extends SubDependencyFactory {
public RoomLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); }
/**
* Dependency provider for <b>compiler</b> with <b>androidx.room:room-compiler</b> coordinates and
* with version reference <b>room</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> getCompiler() {
return create("room.compiler");
}
/**
* Dependency provider for <b>ktx</b> with <b>androidx.room:room-ktx</b> coordinates and
* with version reference <b>room</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> getKtx() {
return create("room.ktx");
}
/**
* Dependency provider for <b>runtime</b> with <b>androidx.room:room-runtime</b> coordinates and
* with version reference <b>room</b>
* <p>
* This dependency was declared in catalog libs.versions.toml
*/
public Provider<MinimalExternalModuleDependency> getRuntime() {
return create("room.runtime");
}
}
public static class VersionAccessors extends VersionFactory {
public VersionAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); }
/**
* Version alias <b>activityCompose</b> with value <b>1.9.0</b>
* <p>
* If the version is a rich version and cannot be represented as a
* single version string, an empty string is returned.
* <p>
* This version was declared in catalog libs.versions.toml
*/
public Provider<String> getActivityCompose() { return getVersion("activityCompose"); }
/**
* Version alias <b>agp</b> with value <b>8.4.1</b>
* <p>
* If the version is a rich version and cannot be represented as a
* single version string, an empty string is returned.
* <p>
* This version was declared in catalog libs.versions.toml
*/
public Provider<String> getAgp() { return getVersion("agp"); }
/**
* Version alias <b>composeBom</b> with value <b>2024.06.00</b>
* <p>
* If the version is a rich version and cannot be represented as a
* single version string, an empty string is returned.
* <p>
* This version was declared in catalog libs.versions.toml
*/
public Provider<String> getComposeBom() { return getVersion("composeBom"); }
/**
* Version alias <b>coreKtx</b> with value <b>1.13.1</b>
* <p>
* If the version is a rich version and cannot be represented as a
* single version string, an empty string is returned.
* <p>
* This version was declared in catalog libs.versions.toml
*/
public Provider<String> getCoreKtx() { return getVersion("coreKtx"); }
/**
* Version alias <b>coroutines</b> with value <b>1.8.1</b>
* <p>
* If the version is a rich version and cannot be represented as a
* single version string, an empty string is returned.
* <p>
* This version was declared in catalog libs.versions.toml
*/
public Provider<String> getCoroutines() { return getVersion("coroutines"); }
/**
* Version alias <b>datastore</b> with value <b>1.1.1</b>
* <p>
* If the version is a rich version and cannot be represented as a
* single version string, an empty string is returned.
* <p>
* This version was declared in catalog libs.versions.toml
*/
public Provider<String> getDatastore() { return getVersion("datastore"); }
/**
* Version alias <b>hilt</b> with value <b>2.51.1</b>
* <p>
* If the version is a rich version and cannot be represented as a
* single version string, an empty string is returned.
* <p>
* This version was declared in catalog libs.versions.toml
*/
public Provider<String> getHilt() { return getVersion("hilt"); }
/**
* Version alias <b>hiltNavigationCompose</b> with value <b>1.2.0</b>
* <p>
* If the version is a rich version and cannot be represented as a
* single version string, an empty string is returned.
* <p>
* This version was declared in catalog libs.versions.toml
*/
public Provider<String> getHiltNavigationCompose() { return getVersion("hiltNavigationCompose"); }
/**
* Version alias <b>kotlin</b> with value <b>2.0.0</b>
* <p>
* If the version is a rich version and cannot be represented as a
* single version string, an empty string is returned.
* <p>
* This version was declared in catalog libs.versions.toml
*/
public Provider<String> getKotlin() { return getVersion("kotlin"); }
/**
* Version alias <b>ksp</b> with value <b>2.0.0-1.0.21</b>
* <p>
* If the version is a rich version and cannot be represented as a
* single version string, an empty string is returned.
* <p>
* This version was declared in catalog libs.versions.toml
*/
public Provider<String> getKsp() { return getVersion("ksp"); }
/**
* Version alias <b>lifecycle</b> with value <b>2.8.2</b>
* <p>
* If the version is a rich version and cannot be represented as a
* single version string, an empty string is returned.
* <p>
* This version was declared in catalog libs.versions.toml
*/
public Provider<String> getLifecycle() { return getVersion("lifecycle"); }
/**
* Version alias <b>navigationCompose</b> with value <b>2.7.7</b>
* <p>
* If the version is a rich version and cannot be represented as a
* single version string, an empty string is returned.
* <p>
* This version was declared in catalog libs.versions.toml
*/
public Provider<String> getNavigationCompose() { return getVersion("navigationCompose"); }
/**
* Version alias <b>room</b> with value <b>2.6.1</b>
* <p>
* If the version is a rich version and cannot be represented as a
* single version string, an empty string is returned.
* <p>
* This version was declared in catalog libs.versions.toml
*/
public Provider<String> getRoom() { return getVersion("room"); }
/**
* Version alias <b>serialization</b> with value <b>1.7.1</b>
* <p>
* If the version is a rich version and cannot be represented as a
* single version string, an empty string is returned.
* <p>
* This version was declared in catalog libs.versions.toml
*/
public Provider<String> 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 <b>hilt</b> with plugin id <b>com.google.dagger.hilt.android</b> and
* with version reference <b>hilt</b>
* <p>
* This plugin was declared in catalog libs.versions.toml
*/
public Provider<PluginDependency> getHilt() { return createPlugin("hilt"); }
/**
* Plugin provider for <b>ksp</b> with plugin id <b>com.google.devtools.ksp</b> and
* with version reference <b>ksp</b>
* <p>
* This plugin was declared in catalog libs.versions.toml
*/
public Provider<PluginDependency> getKsp() { return createPlugin("ksp"); }
/**
* Group of plugins at <b>plugins.android</b>
*/
public AndroidPluginAccessors getAndroid() {
return paccForAndroidPluginAccessors;
}
/**
* Group of plugins at <b>plugins.kotlin</b>
*/
public KotlinPluginAccessors getKotlin() {
return paccForKotlinPluginAccessors;
}
}
public static class AndroidPluginAccessors extends PluginFactory {
public AndroidPluginAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); }
/**
* Plugin provider for <b>android.application</b> with plugin id <b>com.android.application</b> and
* with version reference <b>agp</b>
* <p>
* This plugin was declared in catalog libs.versions.toml
*/
public Provider<PluginDependency> getApplication() { return createPlugin("android.application"); }
}
public static class KotlinPluginAccessors extends PluginFactory {
public KotlinPluginAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); }
/**
* Plugin provider for <b>kotlin.android</b> with plugin id <b>org.jetbrains.kotlin.android</b> and
* with version reference <b>kotlin</b>
* <p>
* This plugin was declared in catalog libs.versions.toml
*/
public Provider<PluginDependency> getAndroid() { return createPlugin("kotlin.android"); }
/**
* Plugin provider for <b>kotlin.compose</b> with plugin id <b>org.jetbrains.kotlin.plugin.compose</b> and
* with version reference <b>kotlin</b>
* <p>
* This plugin was declared in catalog libs.versions.toml
*/
public Provider<PluginDependency> getCompose() { return createPlugin("kotlin.compose"); }
/**
* Plugin provider for <b>kotlin.serialization</b> with plugin id <b>org.jetbrains.kotlin.plugin.serialization</b> and
* with version reference <b>kotlin</b>
* <p>
* This plugin was declared in catalog libs.versions.toml
*/
public Provider<PluginDependency> getSerialization() { return createPlugin("kotlin.serialization"); }
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,2 @@
#Fri May 22 16:56:02 CDT 2026
gradle.version=8.7

View File

@@ -0,0 +1,2 @@
#Fri May 22 16:55:12 CDT 2026
java.home=C\:\\Program Files\\Android\\Android Studio\\jbr

BIN
.gradle/file-system.probe Normal file

Binary file not shown.

3
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

1
.idea/.name generated Normal file
View File

@@ -0,0 +1 @@
HSDiary

6
.idea/AndroidProjectSystem.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AndroidProjectSystem">
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
</component>
</project>

26
.idea/appInsightsSettings.xml generated Normal file
View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AppInsightsSettings">
<option name="tabSettings">
<map>
<entry key="Firebase Crashlytics">
<value>
<InsightsFilterSettings>
<option name="connection">
<ConnectionSetting>
<option name="appId" value="PLACEHOLDER" />
<option name="mobileSdkAppId" value="" />
<option name="projectId" value="" />
<option name="projectNumber" value="" />
</ConnectionSetting>
</option>
<option name="signal" value="SIGNAL_UNSPECIFIED" />
<option name="timeIntervalDays" value="THIRTY_DAYS" />
<option name="visibilityType" value="ALL" />
</InsightsFilterSettings>
</value>
</entry>
</map>
</option>
</component>
</project>

2153
.idea/caches/deviceStreaming.xml generated Normal file

File diff suppressed because it is too large Load Diff

6
.idea/compiler.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" />
</component>
</project>

18
.idea/deploymentTargetSelector.xml generated Normal file
View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2026-05-22T22:22:00.613315300Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\colby\.android\avd\s22_ultra.avd" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
</selectionStates>
</component>
</project>

13
.idea/deviceManager.xml generated Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DeviceTable">
<option name="columnSorters">
<list>
<ColumnSorterState>
<option name="column" value="Name" />
<option name="order" value="ASCENDING" />
</ColumnSorterState>
</list>
</option>
</component>
</project>

18
.idea/gradle.xml generated Normal file
View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

10
.idea/migrations.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

10
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

17
.idea/runConfigurations.xml generated Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
</set>
</option>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

76
app/build.gradle.kts Normal file
View File

@@ -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)
}

2
app/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,2 @@
-keep class com.hsdiary.** { *; }
-keepattributes *Annotation*

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:name=".HSDiaryApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.HSDiary">
<activity
android:name=".MainActivity"
android:exported="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,7 @@
package com.hsdiary
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class HSDiaryApplication : Application()

View File

@@ -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()
}
}
}
}

View File

@@ -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})"
)
}
}
}
}
}

View File

@@ -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<List<ConditionEntryEntity>>
@Query("SELECT * FROM conditions WHERE day_log_id = :dayLogId")
suspend fun getConditionsForDayOnce(dayLogId: Long): List<ConditionEntryEntity>
@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<ConditionEntryEntity>
@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)
}

View File

@@ -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<List<ConditionDefinitionEntity>>
@Query("SELECT * FROM condition_definitions ORDER BY category, sort_order")
suspend fun getAllDefinitionsOnce(): List<ConditionDefinitionEntity>
@Query("SELECT * FROM condition_definitions WHERE profile_visibility = 'ALL' OR profile_visibility = :visibility ORDER BY category, sort_order")
suspend fun getDefinitionsForProfile(visibility: String): List<ConditionDefinitionEntity>
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insertAll(definitions: List<ConditionDefinitionEntity>)
@Query("SELECT COUNT(*) FROM condition_definitions")
suspend fun getCount(): Int
}

View File

@@ -0,0 +1,41 @@
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<List<CycleRecordEntity>>
@Query("SELECT * FROM cycle_records WHERE profile_id = :profileId ORDER BY cycle_start ASC")
suspend fun getCycleRecordsOnce(profileId: Long): List<CycleRecordEntity>
@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?
@Query("SELECT * FROM cycle_records WHERE profile_id = :profileId AND cycle_start = :date LIMIT 1")
suspend fun getByStartDate(profileId: Long, date: String): CycleRecordEntity?
@Query("SELECT * FROM cycle_records WHERE profile_id = :profileId AND cycle_end = :date LIMIT 1")
suspend fun getByEndDate(profileId: Long, date: String): CycleRecordEntity?
@Query("SELECT * FROM cycle_records WHERE profile_id = :profileId AND cycle_start <= :date AND (cycle_end IS NULL OR cycle_end >= :date) LIMIT 1")
suspend fun getRecordContainingDate(profileId: Long, date: String): 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)
}

View File

@@ -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<DayLogEntity?>
@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<List<DayLogEntity>>
@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<DayLogEntity>
@Query("SELECT * FROM day_logs WHERE profile_id = :profileId AND period_active = 1 ORDER BY date ASC")
suspend fun getPeriodDays(profileId: Long): List<DayLogEntity>
@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)
}

View File

@@ -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<List<IntimacyLogEntity>>
@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<IntimacyLogEntity>
@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<String>
@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<IntimacyLogEntity>
@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)
}

View File

@@ -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<List<ProfileEntity>>
@Query("SELECT * FROM profiles ORDER BY created_at ASC")
suspend fun getAllProfilesOnce(): List<ProfileEntity>
@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)
}

View File

@@ -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
)

View File

@@ -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
)

View File

@@ -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
)

View File

@@ -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
)

View File

@@ -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
)

View File

@@ -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 = "{}"
)

View File

@@ -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")
}

View File

@@ -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
}

View File

@@ -0,0 +1,3 @@
package com.hsdiary.data.model
enum class ProfileType { FEMALE, MALE }

View File

@@ -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
)

View File

@@ -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<Preferences> 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<Long?> = context.dataStore.data.map { prefs ->
prefs[Keys.ACTIVE_PROFILE_ID]
}
val firstDayOfWeek: Flow<Int> = context.dataStore.data.map { prefs ->
prefs[Keys.FIRST_DAY_OF_WEEK] ?: 1
}
val appTheme: Flow<String> = context.dataStore.data.map { prefs ->
prefs[Keys.APP_THEME] ?: "SYSTEM"
}
val onboardingComplete: Flow<Boolean> = 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 }
}
}

Some files were not shown because too many files have changed in this diff Show More