commit 375371be4c98fce110efdc22dfcd785289573f7e Author: 15Diego15 Date: Fri May 30 16:33:12 2025 +0200 Add project OrganizaMe diff --git a/.gradle/8.10.2/checksums/checksums.lock b/.gradle/8.10.2/checksums/checksums.lock new file mode 100644 index 0000000..736c114 Binary files /dev/null and b/.gradle/8.10.2/checksums/checksums.lock differ diff --git a/.gradle/8.10.2/checksums/md5-checksums.bin b/.gradle/8.10.2/checksums/md5-checksums.bin new file mode 100644 index 0000000..79e00bd Binary files /dev/null and b/.gradle/8.10.2/checksums/md5-checksums.bin differ diff --git a/.gradle/8.10.2/checksums/sha1-checksums.bin b/.gradle/8.10.2/checksums/sha1-checksums.bin new file mode 100644 index 0000000..8b97e72 Binary files /dev/null and b/.gradle/8.10.2/checksums/sha1-checksums.bin differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidPluginAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidPluginAccessors.class new file mode 100644 index 0000000..6ac6990 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidPluginAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxActivityLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxActivityLibraryAccessors.class new file mode 100644 index 0000000..4402808 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxActivityLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxComposeLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxComposeLibraryAccessors.class new file mode 100644 index 0000000..602f406 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxComposeLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxCoreLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxCoreLibraryAccessors.class new file mode 100644 index 0000000..c2da6ef Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxCoreLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxDatastoreLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxDatastoreLibraryAccessors.class new file mode 100644 index 0000000..2b339be Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxDatastoreLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxEspressoLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxEspressoLibraryAccessors.class new file mode 100644 index 0000000..20677b7 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxEspressoLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxIconsLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxIconsLibraryAccessors.class new file mode 100644 index 0000000..6eba4d8 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxIconsLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxLibraryAccessors.class new file mode 100644 index 0000000..01f3eaa Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxLifecycleLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxLifecycleLibraryAccessors.class new file mode 100644 index 0000000..e8eb3be Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxLifecycleLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxLifecycleRuntimeLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxLifecycleRuntimeLibraryAccessors.class new file mode 100644 index 0000000..ada3a06 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxLifecycleRuntimeLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxRoomLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxRoomLibraryAccessors.class new file mode 100644 index 0000000..d5a408b Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxRoomLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxUiLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxUiLibraryAccessors.class new file mode 100644 index 0000000..2c4313a Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxUiLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxUiTestLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxUiTestLibraryAccessors.class new file mode 100644 index 0000000..0e65fa2 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxUiTestLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxUiToolingLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxUiToolingLibraryAccessors.class new file mode 100644 index 0000000..9db9d16 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$AndroidxUiToolingLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$BundleAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$BundleAccessors.class new file mode 100644 index 0000000..dbc35fd Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$BundleAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$HiltCompilerLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$HiltCompilerLibraryAccessors.class new file mode 100644 index 0000000..47db321 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$HiltCompilerLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$HiltLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$HiltLibraryAccessors.class new file mode 100644 index 0000000..41e2f24 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$HiltLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$HiltNavigationLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$HiltNavigationLibraryAccessors.class new file mode 100644 index 0000000..83b775b Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$HiltNavigationLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$HiltVersionAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$HiltVersionAccessors.class new file mode 100644 index 0000000..4ed5733 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$HiltVersionAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$KotlinPluginAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$KotlinPluginAccessors.class new file mode 100644 index 0000000..a805643 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$KotlinPluginAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$KspVersionAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$KspVersionAccessors.class new file mode 100644 index 0000000..084459e Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$KspVersionAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$MoshiKotlinLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$MoshiKotlinLibraryAccessors.class new file mode 100644 index 0000000..6f5a437 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$MoshiKotlinLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$MoshiLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$MoshiLibraryAccessors.class new file mode 100644 index 0000000..2d198fd Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$MoshiLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$PluginAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$PluginAccessors.class new file mode 100644 index 0000000..684676e Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$PluginAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$VersionAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$VersionAccessors.class new file mode 100644 index 0000000..5b51d73 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs$VersionAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs.class new file mode 100644 index 0000000..305248e Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibs.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidPluginAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidPluginAccessors.class new file mode 100644 index 0000000..79f0455 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidPluginAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxActivityLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxActivityLibraryAccessors.class new file mode 100644 index 0000000..86a91c8 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxActivityLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxComposeLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxComposeLibraryAccessors.class new file mode 100644 index 0000000..1a799e6 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxComposeLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxCoreLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxCoreLibraryAccessors.class new file mode 100644 index 0000000..ab8137e Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxCoreLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxDatastoreLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxDatastoreLibraryAccessors.class new file mode 100644 index 0000000..c2b32f0 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxDatastoreLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxEspressoLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxEspressoLibraryAccessors.class new file mode 100644 index 0000000..cbd37a7 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxEspressoLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxIconsLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxIconsLibraryAccessors.class new file mode 100644 index 0000000..2830913 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxIconsLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxLibraryAccessors.class new file mode 100644 index 0000000..d52ce8d Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxLifecycleLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxLifecycleLibraryAccessors.class new file mode 100644 index 0000000..a85ad96 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxLifecycleLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxLifecycleRuntimeLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxLifecycleRuntimeLibraryAccessors.class new file mode 100644 index 0000000..c2f7a80 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxLifecycleRuntimeLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxRoomLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxRoomLibraryAccessors.class new file mode 100644 index 0000000..30bc6f0 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxRoomLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxUiLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxUiLibraryAccessors.class new file mode 100644 index 0000000..6a47e5c Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxUiLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxUiTestLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxUiTestLibraryAccessors.class new file mode 100644 index 0000000..8c299ca Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxUiTestLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxUiToolingLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxUiToolingLibraryAccessors.class new file mode 100644 index 0000000..38e6890 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$AndroidxUiToolingLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$BundleAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$BundleAccessors.class new file mode 100644 index 0000000..f331c51 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$BundleAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$HiltCompilerLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$HiltCompilerLibraryAccessors.class new file mode 100644 index 0000000..3ef550d Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$HiltCompilerLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$HiltLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$HiltLibraryAccessors.class new file mode 100644 index 0000000..858ebc3 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$HiltLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$HiltNavigationLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$HiltNavigationLibraryAccessors.class new file mode 100644 index 0000000..8bbbce1 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$HiltNavigationLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$HiltVersionAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$HiltVersionAccessors.class new file mode 100644 index 0000000..81186a6 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$HiltVersionAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$KotlinPluginAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$KotlinPluginAccessors.class new file mode 100644 index 0000000..f9ede2b Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$KotlinPluginAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$KspVersionAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$KspVersionAccessors.class new file mode 100644 index 0000000..de9d893 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$KspVersionAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$MoshiKotlinLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$MoshiKotlinLibraryAccessors.class new file mode 100644 index 0000000..6de34c7 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$MoshiKotlinLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$MoshiLibraryAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$MoshiLibraryAccessors.class new file mode 100644 index 0000000..21bf6c0 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$MoshiLibraryAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$PluginAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$PluginAccessors.class new file mode 100644 index 0000000..3dbbe22 Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$PluginAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$VersionAccessors.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$VersionAccessors.class new file mode 100644 index 0000000..345e1ab Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock$VersionAccessors.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock.class b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock.class new file mode 100644 index 0000000..d31a6df Binary files /dev/null and b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/classes/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock.class differ diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/metadata.bin b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/metadata.bin new file mode 100644 index 0000000..6ecc77d --- /dev/null +++ b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/metadata.bin @@ -0,0 +1,2 @@ +vpnuh3dkyna2nmdyzxlvemwzjeY$>1NclassesFɫ* +k%esources^h_å]q \ No newline at end of file diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/sources/org/gradle/accessors/dm/LibrariesForLibs.java b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/sources/org/gradle/accessors/dm/LibrariesForLibs.java new file mode 100644 index 0000000..d5649b6 --- /dev/null +++ b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/sources/org/gradle/accessors/dm/LibrariesForLibs.java @@ -0,0 +1,871 @@ +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 HiltLibraryAccessors laccForHiltLibraryAccessors = new HiltLibraryAccessors(owner); + private final MoshiLibraryAccessors laccForMoshiLibraryAccessors = new MoshiLibraryAccessors(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); + } + + /** + * Dependency provider for junit with junit:junit coordinates and + * with version reference junit + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getJunit() { + return create("junit"); + } + + /** + * Group of libraries at androidx + */ + public AndroidxLibraryAccessors getAndroidx() { + return laccForAndroidxLibraryAccessors; + } + + /** + * Group of libraries at hilt + */ + public HiltLibraryAccessors getHilt() { + return laccForHiltLibraryAccessors; + } + + /** + * Group of libraries at moshi + */ + public MoshiLibraryAccessors getMoshi() { + return laccForMoshiLibraryAccessors; + } + + /** + * 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 AndroidxComposeLibraryAccessors laccForAndroidxComposeLibraryAccessors = new AndroidxComposeLibraryAccessors(owner); + private final AndroidxCoreLibraryAccessors laccForAndroidxCoreLibraryAccessors = new AndroidxCoreLibraryAccessors(owner); + private final AndroidxDatastoreLibraryAccessors laccForAndroidxDatastoreLibraryAccessors = new AndroidxDatastoreLibraryAccessors(owner); + private final AndroidxEspressoLibraryAccessors laccForAndroidxEspressoLibraryAccessors = new AndroidxEspressoLibraryAccessors(owner); + private final AndroidxIconsLibraryAccessors laccForAndroidxIconsLibraryAccessors = new AndroidxIconsLibraryAccessors(owner); + private final AndroidxLifecycleLibraryAccessors laccForAndroidxLifecycleLibraryAccessors = new AndroidxLifecycleLibraryAccessors(owner); + private final AndroidxRoomLibraryAccessors laccForAndroidxRoomLibraryAccessors = new AndroidxRoomLibraryAccessors(owner); + private final AndroidxUiLibraryAccessors laccForAndroidxUiLibraryAccessors = new AndroidxUiLibraryAccessors(owner); + + public AndroidxLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for junit with androidx.test.ext:junit coordinates and + * with version reference junitVersion + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getJunit() { + return create("androidx.junit"); + } + + /** + * 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("androidx.material3"); + } + + /** + * Group of libraries at androidx.activity + */ + public AndroidxActivityLibraryAccessors getActivity() { + return laccForAndroidxActivityLibraryAccessors; + } + + /** + * Group of libraries at androidx.compose + */ + public AndroidxComposeLibraryAccessors getCompose() { + return laccForAndroidxComposeLibraryAccessors; + } + + /** + * Group of libraries at androidx.core + */ + public AndroidxCoreLibraryAccessors getCore() { + return laccForAndroidxCoreLibraryAccessors; + } + + /** + * Group of libraries at androidx.datastore + */ + public AndroidxDatastoreLibraryAccessors getDatastore() { + return laccForAndroidxDatastoreLibraryAccessors; + } + + /** + * Group of libraries at androidx.espresso + */ + public AndroidxEspressoLibraryAccessors getEspresso() { + return laccForAndroidxEspressoLibraryAccessors; + } + + /** + * Group of libraries at androidx.icons + */ + public AndroidxIconsLibraryAccessors getIcons() { + return laccForAndroidxIconsLibraryAccessors; + } + + /** + * Group of libraries at androidx.lifecycle + */ + public AndroidxLifecycleLibraryAccessors getLifecycle() { + return laccForAndroidxLifecycleLibraryAccessors; + } + + /** + * Group of libraries at androidx.room + */ + public AndroidxRoomLibraryAccessors getRoom() { + return laccForAndroidxRoomLibraryAccessors; + } + + /** + * Group of libraries at androidx.ui + */ + public AndroidxUiLibraryAccessors getUi() { + return laccForAndroidxUiLibraryAccessors; + } + + } + + 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 AndroidxComposeLibraryAccessors extends SubDependencyFactory { + + public AndroidxComposeLibraryAccessors(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("androidx.compose.bom"); + } + + } + + 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 AndroidxDatastoreLibraryAccessors extends SubDependencyFactory { + + public AndroidxDatastoreLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for core with androidx.datastore:datastore-core coordinates and + * with version reference dataStore + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getCore() { + return create("androidx.datastore.core"); + } + + /** + * 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("androidx.datastore.preferences"); + } + + } + + public static class AndroidxEspressoLibraryAccessors extends SubDependencyFactory { + + public AndroidxEspressoLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for core with androidx.test.espresso:espresso-core coordinates and + * with version reference espressoCore + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getCore() { + return create("androidx.espresso.core"); + } + + } + + public static class AndroidxIconsLibraryAccessors extends SubDependencyFactory { + + public AndroidxIconsLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for extended with androidx.compose.material:material-icons-extended coordinates and + * with version reference materialIconsExtended + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getExtended() { + return create("androidx.icons.extended"); + } + + } + + public static class AndroidxLifecycleLibraryAccessors extends SubDependencyFactory { + private final AndroidxLifecycleRuntimeLibraryAccessors laccForAndroidxLifecycleRuntimeLibraryAccessors = new AndroidxLifecycleRuntimeLibraryAccessors(owner); + + public AndroidxLifecycleLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Group of libraries at androidx.lifecycle.runtime + */ + public AndroidxLifecycleRuntimeLibraryAccessors getRuntime() { + return laccForAndroidxLifecycleRuntimeLibraryAccessors; + } + + } + + public static class AndroidxLifecycleRuntimeLibraryAccessors extends SubDependencyFactory { + + public AndroidxLifecycleRuntimeLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for ktx with androidx.lifecycle:lifecycle-runtime-ktx coordinates and + * with version reference lifecycleRuntimeKtx + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getKtx() { + return create("androidx.lifecycle.runtime.ktx"); + } + + } + + public static class AndroidxRoomLibraryAccessors extends SubDependencyFactory { + + public AndroidxRoomLibraryAccessors(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("androidx.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("androidx.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("androidx.room.runtime"); + } + + /** + * Dependency provider for testing with androidx.room:room-testing coordinates and + * with version reference room + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getTesting() { + return create("androidx.room.testing"); + } + + } + + public static class AndroidxUiLibraryAccessors extends SubDependencyFactory implements DependencyNotationSupplier { + private final AndroidxUiTestLibraryAccessors laccForAndroidxUiTestLibraryAccessors = new AndroidxUiTestLibraryAccessors(owner); + private final AndroidxUiToolingLibraryAccessors laccForAndroidxUiToolingLibraryAccessors = new AndroidxUiToolingLibraryAccessors(owner); + + public AndroidxUiLibraryAccessors(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("androidx.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("androidx.ui.graphics"); + } + + /** + * Group of libraries at androidx.ui.test + */ + public AndroidxUiTestLibraryAccessors getTest() { + return laccForAndroidxUiTestLibraryAccessors; + } + + /** + * Group of libraries at androidx.ui.tooling + */ + public AndroidxUiToolingLibraryAccessors getTooling() { + return laccForAndroidxUiToolingLibraryAccessors; + } + + } + + public static class AndroidxUiTestLibraryAccessors extends SubDependencyFactory { + + public AndroidxUiTestLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for junit4 with androidx.compose.ui:ui-test-junit4 coordinates and + * with no version specified + *

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

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getManifest() { + return create("androidx.ui.test.manifest"); + } + + } + + public static class AndroidxUiToolingLibraryAccessors extends SubDependencyFactory implements DependencyNotationSupplier { + + public AndroidxUiToolingLibraryAccessors(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("androidx.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("androidx.ui.tooling.preview"); + } + + } + + public static class HiltLibraryAccessors extends SubDependencyFactory { + private final HiltCompilerLibraryAccessors laccForHiltCompilerLibraryAccessors = new HiltCompilerLibraryAccessors(owner); + 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.version + *

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

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getKsp() { + return create("hilt.compiler.ksp"); + } + + } + + 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 androidxHilt + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getCompose() { + return create("hilt.navigation.compose"); + } + + } + + public static class MoshiLibraryAccessors extends SubDependencyFactory implements DependencyNotationSupplier { + private final MoshiKotlinLibraryAccessors laccForMoshiKotlinLibraryAccessors = new MoshiKotlinLibraryAccessors(owner); + + public MoshiLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for moshi with com.squareup.moshi:moshi coordinates and + * with version reference moshi + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider asProvider() { + return create("moshi"); + } + + /** + * Dependency provider for retrofit with com.squareup.retrofit2:converter-moshi coordinates and + * with version reference retrofit + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getRetrofit() { + return create("moshi.retrofit"); + } + + /** + * Group of libraries at moshi.kotlin + */ + public MoshiKotlinLibraryAccessors getKotlin() { + return laccForMoshiKotlinLibraryAccessors; + } + + } + + public static class MoshiKotlinLibraryAccessors extends SubDependencyFactory { + + public MoshiKotlinLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for codegen with com.squareup.moshi:moshi-kotlin-codegen coordinates and + * with version reference moshi + *

+ * This dependency was declared in catalog libs.versions.toml + */ + public Provider getCodegen() { + return create("moshi.kotlin.codegen"); + } + + } + + public static class VersionAccessors extends VersionFactory { + + private final HiltVersionAccessors vaccForHiltVersionAccessors = new HiltVersionAccessors(providers, config); + private final KspVersionAccessors vaccForKspVersionAccessors = new KspVersionAccessors(providers, config); + public VersionAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); } + + /** + * Version alias activityCompose with value 1.10.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 getActivityCompose() { return getVersion("activityCompose"); } + + /** + * Version alias agp with value 8.8.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 getAgp() { return getVersion("agp"); } + + /** + * Version alias androidxHilt 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 getAndroidxHilt() { return getVersion("androidxHilt"); } + + /** + * Version alias composeBom with value 2024.04.01 + *

+ * 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.16.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 getCoreKtx() { return getVersion("coreKtx"); } + + /** + * Version alias dataStore with value 1.1.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 getDataStore() { return getVersion("dataStore"); } + + /** + * Version alias espressoCore with value 3.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 getEspressoCore() { return getVersion("espressoCore"); } + + /** + * Version alias junit with value 4.13.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 getJunit() { return getVersion("junit"); } + + /** + * Version alias junitVersion with value 1.2.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 getJunitVersion() { return getVersion("junitVersion"); } + + /** + * Version alias kotlin with value 2.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 getKotlin() { return getVersion("kotlin"); } + + /** + * Version alias lifecycleRuntimeKtx with value 2.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 getLifecycleRuntimeKtx() { return getVersion("lifecycleRuntimeKtx"); } + + /** + * Version alias materialIconsExtended with value 1.7.8 + *

+ * 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 getMaterialIconsExtended() { return getVersion("materialIconsExtended"); } + + /** + * Version alias moshi with value 1.15.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 getMoshi() { return getVersion("moshi"); } + + /** + * Version alias okhttp with value 4.12.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 getOkhttp() { return getVersion("okhttp"); } + + /** + * Version alias retrofit with value 2.11.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 getRetrofit() { return getVersion("retrofit"); } + + /** + * 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"); } + + /** + * Group of versions at versions.hilt + */ + public HiltVersionAccessors getHilt() { + return vaccForHiltVersionAccessors; + } + + /** + * Group of versions at versions.ksp + */ + public KspVersionAccessors getKsp() { + return vaccForKspVersionAccessors; + } + + } + + public static class HiltVersionAccessors extends VersionFactory { + + public HiltVersionAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); } + + /** + * Version alias hilt.version with value 2.52 + *

+ * 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 getVersion() { return getVersion("hilt.version"); } + + } + + public static class KspVersionAccessors extends VersionFactory { + + public KspVersionAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); } + + /** + * Version alias ksp.version with value 2.0.21-1.0.25 + *

+ * 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 getVersion() { return getVersion("ksp.version"); } + + } + + 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.version + *

+ * 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.version + *

+ * 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"); } + + } + +} diff --git a/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/sources/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock.java b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/sources/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock.java new file mode 100644 index 0000000..723c15f --- /dev/null +++ b/.gradle/8.10.2/dependencies-accessors/6fb7e8f6f44a8b7f3450a1e6a1614af5bd790dc2/sources/org/gradle/accessors/dm/LibrariesForLibsInPluginsBlock.java @@ -0,0 +1,1131 @@ +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 HiltLibraryAccessors laccForHiltLibraryAccessors = new HiltLibraryAccessors(owner); + private final MoshiLibraryAccessors laccForMoshiLibraryAccessors = new MoshiLibraryAccessors(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); + } + + /** + * Dependency provider for junit with junit:junit coordinates and + * with version reference junit + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getJunit() { + 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("junit"); + } + + /** + * 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 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 moshi + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public MoshiLibraryAccessors getMoshi() { + 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 laccForMoshiLibraryAccessors; + } + + /** + * 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 AndroidxComposeLibraryAccessors laccForAndroidxComposeLibraryAccessors = new AndroidxComposeLibraryAccessors(owner); + private final AndroidxCoreLibraryAccessors laccForAndroidxCoreLibraryAccessors = new AndroidxCoreLibraryAccessors(owner); + private final AndroidxDatastoreLibraryAccessors laccForAndroidxDatastoreLibraryAccessors = new AndroidxDatastoreLibraryAccessors(owner); + private final AndroidxEspressoLibraryAccessors laccForAndroidxEspressoLibraryAccessors = new AndroidxEspressoLibraryAccessors(owner); + private final AndroidxIconsLibraryAccessors laccForAndroidxIconsLibraryAccessors = new AndroidxIconsLibraryAccessors(owner); + private final AndroidxLifecycleLibraryAccessors laccForAndroidxLifecycleLibraryAccessors = new AndroidxLifecycleLibraryAccessors(owner); + private final AndroidxRoomLibraryAccessors laccForAndroidxRoomLibraryAccessors = new AndroidxRoomLibraryAccessors(owner); + private final AndroidxUiLibraryAccessors laccForAndroidxUiLibraryAccessors = new AndroidxUiLibraryAccessors(owner); + + public AndroidxLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for junit with androidx.test.ext:junit coordinates and + * with version reference junitVersion + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getJunit() { + 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.junit"); + } + + /** + * 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("androidx.material3"); + } + + /** + * 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.compose + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public AndroidxComposeLibraryAccessors 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 laccForAndroidxComposeLibraryAccessors; + } + + /** + * 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; + } + + /** + * Group of libraries at androidx.datastore + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public AndroidxDatastoreLibraryAccessors 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 laccForAndroidxDatastoreLibraryAccessors; + } + + /** + * Group of libraries at androidx.espresso + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public AndroidxEspressoLibraryAccessors getEspresso() { + 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 laccForAndroidxEspressoLibraryAccessors; + } + + /** + * Group of libraries at androidx.icons + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public AndroidxIconsLibraryAccessors 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 laccForAndroidxIconsLibraryAccessors; + } + + /** + * Group of libraries at androidx.lifecycle + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public AndroidxLifecycleLibraryAccessors 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 laccForAndroidxLifecycleLibraryAccessors; + } + + /** + * Group of libraries at androidx.room + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public AndroidxRoomLibraryAccessors 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 laccForAndroidxRoomLibraryAccessors; + } + + /** + * Group of libraries at androidx.ui + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public AndroidxUiLibraryAccessors 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 laccForAndroidxUiLibraryAccessors; + } + + } + + /** + * @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 AndroidxComposeLibraryAccessors extends SubDependencyFactory { + + public AndroidxComposeLibraryAccessors(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("androidx.compose.bom"); + } + + } + + /** + * @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 AndroidxDatastoreLibraryAccessors extends SubDependencyFactory { + + public AndroidxDatastoreLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for core with androidx.datastore:datastore-core 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 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 create("androidx.datastore.core"); + } + + /** + * 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("androidx.datastore.preferences"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class AndroidxEspressoLibraryAccessors extends SubDependencyFactory { + + public AndroidxEspressoLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for core with androidx.test.espresso:espresso-core coordinates and + * with version reference espressoCore + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider 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 create("androidx.espresso.core"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class AndroidxIconsLibraryAccessors extends SubDependencyFactory { + + public AndroidxIconsLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for extended with androidx.compose.material:material-icons-extended coordinates and + * with version reference materialIconsExtended + *

+ * 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("androidx.icons.extended"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class AndroidxLifecycleLibraryAccessors extends SubDependencyFactory { + private final AndroidxLifecycleRuntimeLibraryAccessors laccForAndroidxLifecycleRuntimeLibraryAccessors = new AndroidxLifecycleRuntimeLibraryAccessors(owner); + + public AndroidxLifecycleLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Group of libraries at androidx.lifecycle.runtime + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public AndroidxLifecycleRuntimeLibraryAccessors 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 laccForAndroidxLifecycleRuntimeLibraryAccessors; + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class AndroidxLifecycleRuntimeLibraryAccessors extends SubDependencyFactory { + + public AndroidxLifecycleRuntimeLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for ktx with androidx.lifecycle:lifecycle-runtime-ktx coordinates and + * with version reference lifecycleRuntimeKtx + *

+ * 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.lifecycle.runtime.ktx"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class AndroidxRoomLibraryAccessors extends SubDependencyFactory { + + public AndroidxRoomLibraryAccessors(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("androidx.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("androidx.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("androidx.room.runtime"); + } + + /** + * Dependency provider for testing with androidx.room:room-testing 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 getTesting() { + 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.room.testing"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class AndroidxUiLibraryAccessors extends SubDependencyFactory implements DependencyNotationSupplier { + private final AndroidxUiTestLibraryAccessors laccForAndroidxUiTestLibraryAccessors = new AndroidxUiTestLibraryAccessors(owner); + private final AndroidxUiToolingLibraryAccessors laccForAndroidxUiToolingLibraryAccessors = new AndroidxUiToolingLibraryAccessors(owner); + + public AndroidxUiLibraryAccessors(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("androidx.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("androidx.ui.graphics"); + } + + /** + * Group of libraries at androidx.ui.test + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public AndroidxUiTestLibraryAccessors getTest() { + 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 laccForAndroidxUiTestLibraryAccessors; + } + + /** + * Group of libraries at androidx.ui.tooling + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public AndroidxUiToolingLibraryAccessors 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 laccForAndroidxUiToolingLibraryAccessors; + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class AndroidxUiTestLibraryAccessors extends SubDependencyFactory { + + public AndroidxUiTestLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for junit4 with androidx.compose.ui:ui-test-junit4 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 getJunit4() { + 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.ui.test.junit4"); + } + + /** + * Dependency provider for manifest with androidx.compose.ui:ui-test-manifest 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 getManifest() { + 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.ui.test.manifest"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class AndroidxUiToolingLibraryAccessors extends SubDependencyFactory implements DependencyNotationSupplier { + + public AndroidxUiToolingLibraryAccessors(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("androidx.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("androidx.ui.tooling.preview"); + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class HiltLibraryAccessors extends SubDependencyFactory { + private final HiltCompilerLibraryAccessors laccForHiltCompilerLibraryAccessors = new HiltCompilerLibraryAccessors(owner); + 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.version + *

+ * 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"); + } + + /** + * Group of libraries at hilt.compiler + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public HiltCompilerLibraryAccessors 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 laccForHiltCompilerLibraryAccessors; + } + + /** + * 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 HiltCompilerLibraryAccessors extends SubDependencyFactory { + + public HiltCompilerLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for ksp with com.google.dagger:hilt-android-compiler coordinates and + * with version reference hilt.version + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getKsp() { + 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.ksp"); + } + + } + + /** + * @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 androidxHilt + *

+ * 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 MoshiLibraryAccessors extends SubDependencyFactory implements DependencyNotationSupplier { + private final MoshiKotlinLibraryAccessors laccForMoshiKotlinLibraryAccessors = new MoshiKotlinLibraryAccessors(owner); + + public MoshiLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for moshi with com.squareup.moshi:moshi coordinates and + * with version reference moshi + *

+ * 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("moshi"); + } + + /** + * Dependency provider for retrofit with com.squareup.retrofit2:converter-moshi coordinates and + * with version reference retrofit + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getRetrofit() { + 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("moshi.retrofit"); + } + + /** + * Group of libraries at moshi.kotlin + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public MoshiKotlinLibraryAccessors getKotlin() { + 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 laccForMoshiKotlinLibraryAccessors; + } + + } + + /** + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public static class MoshiKotlinLibraryAccessors extends SubDependencyFactory { + + public MoshiKotlinLibraryAccessors(AbstractExternalDependencyFactory owner) { super(owner); } + + /** + * Dependency provider for codegen with com.squareup.moshi:moshi-kotlin-codegen coordinates and + * with version reference moshi + *

+ * This dependency was declared in catalog libs.versions.toml + * + * @deprecated Will be removed in Gradle 9.0. + */ + @Deprecated + public Provider getCodegen() { + 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("moshi.kotlin.codegen"); + } + + } + + public static class VersionAccessors extends VersionFactory { + + private final HiltVersionAccessors vaccForHiltVersionAccessors = new HiltVersionAccessors(providers, config); + private final KspVersionAccessors vaccForKspVersionAccessors = new KspVersionAccessors(providers, config); + public VersionAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); } + + /** + * Version alias activityCompose with value 1.10.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 getActivityCompose() { return getVersion("activityCompose"); } + + /** + * Version alias agp with value 8.8.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 getAgp() { return getVersion("agp"); } + + /** + * Version alias androidxHilt 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 getAndroidxHilt() { return getVersion("androidxHilt"); } + + /** + * Version alias composeBom with value 2024.04.01 + *

+ * 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.16.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 getCoreKtx() { return getVersion("coreKtx"); } + + /** + * Version alias dataStore with value 1.1.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 getDataStore() { return getVersion("dataStore"); } + + /** + * Version alias espressoCore with value 3.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 getEspressoCore() { return getVersion("espressoCore"); } + + /** + * Version alias junit with value 4.13.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 getJunit() { return getVersion("junit"); } + + /** + * Version alias junitVersion with value 1.2.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 getJunitVersion() { return getVersion("junitVersion"); } + + /** + * Version alias kotlin with value 2.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 getKotlin() { return getVersion("kotlin"); } + + /** + * Version alias lifecycleRuntimeKtx with value 2.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 getLifecycleRuntimeKtx() { return getVersion("lifecycleRuntimeKtx"); } + + /** + * Version alias materialIconsExtended with value 1.7.8 + *

+ * 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 getMaterialIconsExtended() { return getVersion("materialIconsExtended"); } + + /** + * Version alias moshi with value 1.15.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 getMoshi() { return getVersion("moshi"); } + + /** + * Version alias okhttp with value 4.12.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 getOkhttp() { return getVersion("okhttp"); } + + /** + * Version alias retrofit with value 2.11.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 getRetrofit() { return getVersion("retrofit"); } + + /** + * 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"); } + + /** + * Group of versions at versions.hilt + */ + public HiltVersionAccessors getHilt() { + return vaccForHiltVersionAccessors; + } + + /** + * Group of versions at versions.ksp + */ + public KspVersionAccessors getKsp() { + return vaccForKspVersionAccessors; + } + + } + + public static class HiltVersionAccessors extends VersionFactory { + + public HiltVersionAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); } + + /** + * Version alias hilt.version with value 2.52 + *

+ * 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 getVersion() { return getVersion("hilt.version"); } + + } + + public static class KspVersionAccessors extends VersionFactory { + + public KspVersionAccessors(ProviderFactory providers, DefaultVersionCatalog config) { super(providers, config); } + + /** + * Version alias ksp.version with value 2.0.21-1.0.25 + *

+ * 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 getVersion() { return getVersion("ksp.version"); } + + } + + /** + * @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.version + *

+ * 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.version + *

+ * 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"); } + + } + +} diff --git a/.gradle/8.10.2/dependencies-accessors/gc.properties b/.gradle/8.10.2/dependencies-accessors/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/8.10.2/executionHistory/executionHistory.bin b/.gradle/8.10.2/executionHistory/executionHistory.bin new file mode 100644 index 0000000..ab92717 Binary files /dev/null and b/.gradle/8.10.2/executionHistory/executionHistory.bin differ diff --git a/.gradle/8.10.2/executionHistory/executionHistory.lock b/.gradle/8.10.2/executionHistory/executionHistory.lock new file mode 100644 index 0000000..a9cfaa8 Binary files /dev/null and b/.gradle/8.10.2/executionHistory/executionHistory.lock differ diff --git a/.gradle/8.10.2/fileChanges/last-build.bin b/.gradle/8.10.2/fileChanges/last-build.bin new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/.gradle/8.10.2/fileChanges/last-build.bin differ diff --git a/.gradle/8.10.2/fileHashes/fileHashes.bin b/.gradle/8.10.2/fileHashes/fileHashes.bin new file mode 100644 index 0000000..ec78a58 Binary files /dev/null and b/.gradle/8.10.2/fileHashes/fileHashes.bin differ diff --git a/.gradle/8.10.2/fileHashes/fileHashes.lock b/.gradle/8.10.2/fileHashes/fileHashes.lock new file mode 100644 index 0000000..7322118 Binary files /dev/null and b/.gradle/8.10.2/fileHashes/fileHashes.lock differ diff --git a/.gradle/8.10.2/fileHashes/resourceHashesCache.bin b/.gradle/8.10.2/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000..ec9b7b6 Binary files /dev/null and b/.gradle/8.10.2/fileHashes/resourceHashesCache.bin differ diff --git a/.gradle/8.10.2/gc.properties b/.gradle/8.10.2/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000..64b84a8 Binary files /dev/null and b/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000..1590ccb --- /dev/null +++ b/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Fri May 30 10:33:29 CEST 2025 +gradle.version=8.10.2 diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000..5ff6bce Binary files /dev/null and b/.gradle/buildOutputCleanup/outputFiles.bin differ diff --git a/.gradle/config.properties b/.gradle/config.properties new file mode 100644 index 0000000..e79220b --- /dev/null +++ b/.gradle/config.properties @@ -0,0 +1,2 @@ +#Fri May 30 10:34:53 CEST 2025 +java.home=/Applications/Android Studio.app/Contents/jbr/Contents/Home diff --git a/.gradle/file-system.probe b/.gradle/file-system.probe new file mode 100644 index 0000000..fdef657 Binary files /dev/null and b/.gradle/file-system.probe differ diff --git a/.gradle/vcs-1/gc.properties b/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000..e69de29 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/.name b/.idea/.name new file mode 100644 index 0000000..3b2ddf6 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +OrganizaMe \ No newline at end of file diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml new file mode 100644 index 0000000..74a20ba --- /dev/null +++ b/.idea/assetWizardSettings.xml @@ -0,0 +1,292 @@ + + + + + + \ No newline at end of file diff --git a/.idea/caches/deviceStreaming.xml b/.idea/caches/deviceStreaming.xml new file mode 100644 index 0000000..64723d0 --- /dev/null +++ b/.idea/caches/deviceStreaming.xml @@ -0,0 +1,703 @@ + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b86273d --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..7b3006b --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..cde3e19 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,57 @@ + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..c224ad5 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ 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..b2c751a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..804e364 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/app/OrganizaMe.app.iml b/.idea/modules/app/OrganizaMe.app.iml new file mode 100644 index 0000000..000c095 --- /dev/null +++ b/.idea/modules/app/OrganizaMe.app.iml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/modules/app/OrganizaMe.app.main.iml b/.idea/modules/app/OrganizaMe.app.main.iml new file mode 100644 index 0000000..fc6f978 --- /dev/null +++ b/.idea/modules/app/OrganizaMe.app.main.iml @@ -0,0 +1,8 @@ + + + + + + + + \ 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/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..6f58cb4 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,84 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) + alias(libs.plugins.hilt) + alias(libs.plugins.ksp) +} + +android { + namespace = "com.diegocayo.organizame" + compileSdk = 35 + + defaultConfig { + applicationId = "com.diegocayo.organizame" + minSdk = 30 + targetSdk = 35 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + compose = true + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.ui.test.junit4) + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) + implementation(libs.androidx.icons.extended) + + // Hilt + implementation(libs.hilt.android) + implementation(libs.hilt.navigation.compose) + ksp(libs.hilt.compiler.ksp) + + + // Retrofit + implementation(libs.moshi) + implementation(libs.moshi.retrofit) + ksp(libs.moshi.kotlin.codegen) + + + // DataStore + implementation(libs.androidx.datastore.preferences) + implementation(libs.androidx.datastore.core) + + // Room + implementation(libs.androidx.room.runtime) + implementation(libs.androidx.room.ktx) + ksp(libs.androidx.room.compiler) + testImplementation(libs.androidx.room.testing) +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/com/diegocayo/organizame/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/diegocayo/organizame/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..b57e960 --- /dev/null +++ b/app/src/androidTest/java/com/diegocayo/organizame/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.diegocayo.organizame + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.diegocayo.organizame", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6f87191 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000..d608d04 Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/java/com/diegocayo/organizame/OrganizaMeApp.kt b/app/src/main/java/com/diegocayo/organizame/OrganizaMeApp.kt new file mode 100644 index 0000000..f4e3d3c --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/OrganizaMeApp.kt @@ -0,0 +1,7 @@ +package com.diegocayo.organizame + +import android.app.Application +import dagger.hilt.android.HiltAndroidApp + +@HiltAndroidApp +class OrganizaMeApp : Application() \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/di/DataModule.kt b/app/src/main/java/com/diegocayo/organizame/data/di/DataModule.kt new file mode 100644 index 0000000..00dffbd --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/di/DataModule.kt @@ -0,0 +1,65 @@ +package com.diegocayo.organizame.data.di + +import android.content.Context +import com.diegocayo.organizame.data.local.datasource.PreferencesDataSource +import com.diegocayo.organizame.data.local.datasource.PreferencesDataSourceImpl +import com.diegocayo.organizame.data.repository.LoginRepositoryImpl +import com.diegocayo.organizame.data.repository.UserRepositoryImpl +import com.diegocayo.organizame.domain.repository.LoginRepository +import com.diegocayo.organizame.domain.repository.UserRepository +import com.diegocayo.organizame.utils.moshi.MoshiParser +import com.squareup.moshi.Moshi +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 DataModule { + + @Provides + @Singleton + fun providePreferencesDataSource( + context: Context, + moshiParser: MoshiParser + ): PreferencesDataSource { + return PreferencesDataSourceImpl(context, moshiParser) + } + + @Provides + @Singleton + internal fun provideMoshi(): Moshi { + return Moshi.Builder().build() + } + + @Provides + @Singleton + internal fun provideMoshiParser(moshi: Moshi): MoshiParser { + return MoshiParser(moshi) + } + + @Provides + @Singleton + fun provideUserRepository( + preferencesDataSource: PreferencesDataSource + ): UserRepository { + return UserRepositoryImpl(preferencesDataSource) + } + + @Provides + @Singleton + fun provideLoginRepository( + preferencesDataSource: PreferencesDataSource + ): LoginRepository { + return LoginRepositoryImpl(preferencesDataSource) + } + + @Provides + @Singleton + fun provideContext(@ApplicationContext context: Context): Context { + return context + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/di/DatabaseModule.kt b/app/src/main/java/com/diegocayo/organizame/data/di/DatabaseModule.kt new file mode 100644 index 0000000..0d90337 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/di/DatabaseModule.kt @@ -0,0 +1,86 @@ +package com.diegocayo.organizame.data.di + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.PreferenceDataStoreFactory +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.preferencesDataStoreFile +import androidx.room.Room +import com.diegocayo.organizame.data.local.OrganizaMeDatabase +import com.diegocayo.organizame.data.local.dao.EventDao +import com.diegocayo.organizame.data.local.dao.SubjectDao +import com.diegocayo.organizame.data.local.dao.TaskDao +import com.diegocayo.organizame.data.repository.EventRepositoryImpl +import com.diegocayo.organizame.data.repository.SubjectRepositoryImpl +import com.diegocayo.organizame.data.repository.TaskRepositoryImpl +import com.diegocayo.organizame.domain.repository.EventRepository +import com.diegocayo.organizame.domain.repository.SubjectRepository +import com.diegocayo.organizame.domain.repository.TaskRepository +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 { + + private const val PREFERENCES_NAME = "organizame_preferences" + + @Provides + @Singleton + fun provideDatabase( + @ApplicationContext context: Context + ): OrganizaMeDatabase = Room.databaseBuilder( + context, + OrganizaMeDatabase::class.java, + "organizame_database" + ) + .addMigrations( + OrganizaMeDatabase.MIGRATION_2_3, + OrganizaMeDatabase.MIGRATION_3_4 + ) + .build() + + @Provides + @Singleton + fun provideDataStore( + @ApplicationContext context: Context + ): DataStore = PreferenceDataStoreFactory.create( + produceFile = { context.preferencesDataStoreFile(PREFERENCES_NAME) } + ) + + @Provides + @Singleton + fun provideSubjectDao(database: OrganizaMeDatabase): SubjectDao = database.subjectDao() + + @Provides + @Singleton + fun provideTaskDao(database: OrganizaMeDatabase): TaskDao = database.taskDao() + + @Provides + @Singleton + fun provideEventDao(database: OrganizaMeDatabase): EventDao = database.eventDao() + + @Provides + @Singleton + fun provideSubjectRepository( + subjectDao: SubjectDao + ): SubjectRepository = SubjectRepositoryImpl(subjectDao) + + @Provides + @Singleton + fun provideTaskRepository( + taskDao: TaskDao, + subjectRepository: SubjectRepository + ): TaskRepository = TaskRepositoryImpl(taskDao, subjectRepository) + + @Provides + @Singleton + fun provideEventRepository( + eventDao: EventDao, + subjectRepository: SubjectRepository + ): EventRepository = EventRepositoryImpl(eventDao, subjectRepository) +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/local/OrganizaMeDatabase.kt b/app/src/main/java/com/diegocayo/organizame/data/local/OrganizaMeDatabase.kt new file mode 100644 index 0000000..b1b8a78 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/local/OrganizaMeDatabase.kt @@ -0,0 +1,57 @@ +package com.diegocayo.organizame.data.local + +import androidx.room.Database +import androidx.room.RoomDatabase +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase +import com.diegocayo.organizame.data.local.dao.EventDao +import com.diegocayo.organizame.data.local.dao.SubjectDao +import com.diegocayo.organizame.data.local.dao.TaskDao +import com.diegocayo.organizame.data.local.entity.EventEntity +import com.diegocayo.organizame.data.local.entity.SubjectEntity +import com.diegocayo.organizame.data.local.entity.TaskEntity + +@Database( + entities = [ + SubjectEntity::class, + TaskEntity::class, + EventEntity::class + ], + version = 4, + exportSchema = false +) +abstract class OrganizaMeDatabase : RoomDatabase() { + abstract fun subjectDao(): SubjectDao + abstract fun taskDao(): TaskDao + abstract fun eventDao(): EventDao + + companion object { + val MIGRATION_2_3 = object : Migration(2, 3) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL( + "ALTER TABLE tasks ADD COLUMN scheduledDate INTEGER NOT NULL DEFAULT ${System.currentTimeMillis()}" + ) + } + } + + val MIGRATION_3_4 = object : Migration(3, 4) { + override fun migrate(database: SupportSQLiteDatabase) { + database.execSQL( + """ + CREATE TABLE events ( + id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + title TEXT NOT NULL, + description TEXT NOT NULL, + subjectId INTEGER, + date INTEGER NOT NULL, + startTime INTEGER NOT NULL, + endTime INTEGER NOT NULL, + createdAt INTEGER NOT NULL, + FOREIGN KEY(subjectId) REFERENCES subjects(id) ON DELETE SET NULL + ) + """ + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/local/dao/EventDao.kt b/app/src/main/java/com/diegocayo/organizame/data/local/dao/EventDao.kt new file mode 100644 index 0000000..49519a4 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/local/dao/EventDao.kt @@ -0,0 +1,34 @@ +package com.diegocayo.organizame.data.local.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Update +import com.diegocayo.organizame.data.local.entity.EventEntity +import kotlinx.coroutines.flow.Flow + +@Dao +interface EventDao { + @Query("SELECT * FROM events ORDER BY date ASC, startTime ASC") + fun getAllEvents(): Flow> + + @Query( + """ + SELECT * FROM events + WHERE date >= :startOfDay AND date < :endOfDay + ORDER BY startTime ASC + """ + ) + fun getEventsByDate(startOfDay: Long, endOfDay: Long): Flow> + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertEvent(event: EventEntity): Long + + @Update + suspend fun updateEvent(event: EventEntity) + + @Delete + suspend fun deleteEvent(event: EventEntity) +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/local/dao/SubjectDao.kt b/app/src/main/java/com/diegocayo/organizame/data/local/dao/SubjectDao.kt new file mode 100644 index 0000000..5aaef13 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/local/dao/SubjectDao.kt @@ -0,0 +1,31 @@ +package com.diegocayo.organizame.data.local.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import androidx.room.Update +import com.diegocayo.organizame.data.local.entity.SubjectEntity +import kotlinx.coroutines.flow.Flow + +@Dao +interface SubjectDao { + @Query("SELECT * FROM subjects") + fun getAllSubjects(): Flow> + + @Query("SELECT * FROM subjects WHERE id = :id") + suspend fun getSubjectById(id: Long): SubjectEntity? + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun insertSubject(subject: SubjectEntity): Long + + @Update + suspend fun updateSubject(subject: SubjectEntity) + + @Delete + suspend fun deleteSubject(subject: SubjectEntity) + + @Query("DELETE FROM subjects") + suspend fun deleteAllSubjects() +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/local/dao/TaskDao.kt b/app/src/main/java/com/diegocayo/organizame/data/local/dao/TaskDao.kt new file mode 100644 index 0000000..afd6161 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/local/dao/TaskDao.kt @@ -0,0 +1,36 @@ +package com.diegocayo.organizame.data.local.dao + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.Query +import androidx.room.Update +import com.diegocayo.organizame.data.local.entity.TaskEntity +import kotlinx.coroutines.flow.Flow + +@Dao +interface TaskDao { + @Query("SELECT * FROM tasks ORDER BY createdAt DESC") + fun getAllTasks(): Flow> + + @Query("SELECT * FROM tasks WHERE status = 'PENDING' ORDER BY createdAt DESC") + fun getPendingTasks(): Flow> + + @Query("SELECT * FROM tasks WHERE status = 'COMPLETED' ORDER BY createdAt DESC") + fun getCompletedTasks(): Flow> + + @Query("SELECT * FROM tasks WHERE id = :taskId") + suspend fun getTaskById(taskId: Long): TaskEntity? + + @Insert + suspend fun insertTask(task: TaskEntity): Long + + @Update + suspend fun updateTask(task: TaskEntity) + + @Delete + suspend fun deleteTask(task: TaskEntity) + + @Query("UPDATE tasks SET status = :status WHERE id = :taskId") + suspend fun updateTaskStatus(taskId: Long, status: String) +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/local/datasource/PreferencesDataSource.kt b/app/src/main/java/com/diegocayo/organizame/data/local/datasource/PreferencesDataSource.kt new file mode 100644 index 0000000..6fd2369 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/local/datasource/PreferencesDataSource.kt @@ -0,0 +1,76 @@ +package com.diegocayo.organizame.data.local.datasource + +import android.content.Context +import androidx.datastore.preferences.core.booleanPreferencesKey +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.stringPreferencesKey +import androidx.datastore.preferences.preferencesDataStore +import com.diegocayo.organizame.data.local.dto.UserDTO +import com.diegocayo.organizame.utils.moshi.MoshiParser +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map +import javax.inject.Inject +import javax.inject.Singleton + +interface PreferencesDataSource { + suspend fun saveUser(user: UserDTO) + suspend fun getUser(): UserDTO? + suspend fun setLoginStatus(isLoggedIn: Boolean) + suspend fun isLoggedIn(): Boolean + suspend fun clearUser() + suspend fun clear() +} + +private val Context.dataStore by preferencesDataStore("app_prefs") + +@Singleton +class PreferencesDataSourceImpl @Inject constructor( + private val context: Context, + private val moshiParser: MoshiParser +) : PreferencesDataSource { + + companion object { + private val KEY_USER_DATA = stringPreferencesKey("key_user_data") + private val KEY_IS_LOGGED_IN = booleanPreferencesKey("key_is_logged_in") + } + + override suspend fun saveUser(user: UserDTO) { + val json = moshiParser.toJson(user, UserDTO::class.java) + context.dataStore.edit { preferences -> + preferences[KEY_USER_DATA] = json + } + } + + override suspend fun getUser(): UserDTO? { + val json = context.dataStore.data + .map { preferences -> preferences[KEY_USER_DATA] } + .first() + return json?.let { + moshiParser.fromJson(it, UserDTO::class.java) + } + } + + override suspend fun setLoginStatus(isLoggedIn: Boolean) { + context.dataStore.edit { preferences -> + preferences[KEY_IS_LOGGED_IN] = isLoggedIn + } + } + + override suspend fun isLoggedIn(): Boolean { + return context.dataStore.data + .map { preferences -> preferences[KEY_IS_LOGGED_IN] ?: false } + .first() + } + + override suspend fun clearUser() { + context.dataStore.edit { preferences -> + preferences.remove(KEY_USER_DATA) + } + } + + override suspend fun clear() { + context.dataStore.edit { preferences -> + preferences.clear() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/local/dto/UserDTO.kt b/app/src/main/java/com/diegocayo/organizame/data/local/dto/UserDTO.kt new file mode 100644 index 0000000..252be70 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/local/dto/UserDTO.kt @@ -0,0 +1,11 @@ +package com.diegocayo.organizame.data.local.dto + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class UserDTO( + @Json(name = "name") val name: String, + @Json(name = "surname") val surname: String, + @Json(name = "birthdate") val birthdate: String +) \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/local/entity/EventEntity.kt b/app/src/main/java/com/diegocayo/organizame/data/local/entity/EventEntity.kt new file mode 100644 index 0000000..8c671f4 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/local/entity/EventEntity.kt @@ -0,0 +1,28 @@ +package com.diegocayo.organizame.data.local.entity + +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.PrimaryKey + +@Entity( + tableName = "events", + foreignKeys = [ + ForeignKey( + entity = SubjectEntity::class, + parentColumns = ["id"], + childColumns = ["subjectId"], + onDelete = ForeignKey.SET_NULL + ) + ] +) +data class EventEntity( + @PrimaryKey(autoGenerate = true) + val id: Long = 0, + val title: String, + val description: String, + val subjectId: Long?, + val date: Long, + val startTime: Long, + val endTime: Long, + val createdAt: Long = System.currentTimeMillis() +) \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/local/entity/SubjectEntity.kt b/app/src/main/java/com/diegocayo/organizame/data/local/entity/SubjectEntity.kt new file mode 100644 index 0000000..2d6fe71 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/local/entity/SubjectEntity.kt @@ -0,0 +1,13 @@ +package com.diegocayo.organizame.data.local.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "subjects") +data class SubjectEntity( + @PrimaryKey(autoGenerate = true) + val id: Long = 0, + val name: String, + val abbreviation: String, + val color: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/local/entity/TaskEntity.kt b/app/src/main/java/com/diegocayo/organizame/data/local/entity/TaskEntity.kt new file mode 100644 index 0000000..0fa5a16 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/local/entity/TaskEntity.kt @@ -0,0 +1,36 @@ +package com.diegocayo.organizame.data.local.entity + +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.PrimaryKey + +@Entity( + tableName = "tasks", + foreignKeys = [ + ForeignKey( + entity = SubjectEntity::class, + parentColumns = ["id"], + childColumns = ["subjectId"], + onDelete = ForeignKey.SET_NULL + ) + ] +) +data class TaskEntity( + @PrimaryKey(autoGenerate = true) + val id: Long = 0, + val title: String, + val description: String, + val subjectId: Long?, + val priority: TaskPriority, + val status: TaskStatus, + val scheduledDate: Long = System.currentTimeMillis(), + val createdAt: Long = System.currentTimeMillis() +) + +enum class TaskPriority { + HIGH, MEDIUM, LOW +} + +enum class TaskStatus { + PENDING, COMPLETED +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/local/preferences/PreferencesDataStore.kt b/app/src/main/java/com/diegocayo/organizame/data/local/preferences/PreferencesDataStore.kt new file mode 100644 index 0000000..e433c4f --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/local/preferences/PreferencesDataStore.kt @@ -0,0 +1,44 @@ +package com.diegocayo.organizame.data.local.preferences + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.emptyPreferences +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.flow.first +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class PreferencesDataStore @Inject constructor( + @ApplicationContext private val context: Context, + private val dataStore: DataStore +) { + suspend fun clearPreferences() { + try { + val currentPrefs = dataStore.data.first() + + currentPrefs.asMap().keys.forEach { key -> + dataStore.edit { preferences -> + preferences.remove(key) + } + } + + dataStore.edit { preferences -> + preferences.clear() + } + + val emptyPrefs = dataStore.data.first() + if (emptyPrefs != emptyPreferences()) { + dataStore.edit { preferences -> + preferences.clear() + } + } + } catch (e: Exception) { + dataStore.edit { preferences -> + preferences.clear() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/mapper/EventMapper.kt b/app/src/main/java/com/diegocayo/organizame/data/mapper/EventMapper.kt new file mode 100644 index 0000000..16d43b2 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/mapper/EventMapper.kt @@ -0,0 +1,31 @@ +package com.diegocayo.organizame.data.mapper + +import com.diegocayo.organizame.data.local.entity.EventEntity +import com.diegocayo.organizame.domain.model.Event +import com.diegocayo.organizame.domain.model.Subject + +fun EventEntity.toModel(subject: Subject? = null): Event { + return Event( + id = id, + title = title, + description = description, + subject = subject, + date = date, + startTime = startTime, + endTime = endTime, + createdAt = createdAt + ) +} + +fun Event.toEntity(): EventEntity { + return EventEntity( + id = id, + title = title, + description = description, + subjectId = subject?.id, + date = date, + startTime = startTime, + endTime = endTime, + createdAt = createdAt + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/mapper/SubjectMapper.kt b/app/src/main/java/com/diegocayo/organizame/data/mapper/SubjectMapper.kt new file mode 100644 index 0000000..99f370f --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/mapper/SubjectMapper.kt @@ -0,0 +1,19 @@ +package com.diegocayo.organizame.data.mapper + +import com.diegocayo.organizame.data.local.entity.SubjectEntity +import com.diegocayo.organizame.domain.model.Subject + +fun SubjectEntity.toModel() = Subject( + id = id, + name = name, + abbreviation = abbreviation, + color = color, + +) + +fun Subject.toEntity() = SubjectEntity( + id = id, + name = name, + abbreviation = abbreviation, + color = color +) \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/mapper/TaskMapper.kt b/app/src/main/java/com/diegocayo/organizame/data/mapper/TaskMapper.kt new file mode 100644 index 0000000..596ebe5 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/mapper/TaskMapper.kt @@ -0,0 +1,31 @@ +package com.diegocayo.organizame.data.mapper + +import com.diegocayo.organizame.data.local.entity.TaskEntity +import com.diegocayo.organizame.domain.model.Subject +import com.diegocayo.organizame.domain.model.Task + +fun TaskEntity.toModel(subject: Subject? = null): Task { + return Task( + id = id, + title = title, + description = description, + subject = subject, + priority = priority, + status = status, + scheduledDate = scheduledDate, + createdAt = createdAt + ) +} + +fun Task.toEntity(): TaskEntity { + return TaskEntity( + id = id, + title = title, + description = description, + subjectId = subject?.id, + priority = priority, + status = status, + scheduledDate = scheduledDate, + createdAt = createdAt + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/mapper/UserMapper.kt b/app/src/main/java/com/diegocayo/organizame/data/mapper/UserMapper.kt new file mode 100644 index 0000000..fe51e24 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/mapper/UserMapper.kt @@ -0,0 +1,16 @@ +package com.diegocayo.organizame.data.mapper + +import com.diegocayo.organizame.data.local.dto.UserDTO +import com.diegocayo.organizame.domain.model.User + +fun User.toDto() = UserDTO( + name = name, + surname = surname, + birthdate = birthdate +) + +fun UserDTO.toDomain() = User( + name = name, + surname = surname, + birthdate = birthdate +) \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/repository/EventRepositoryImpl.kt b/app/src/main/java/com/diegocayo/organizame/data/repository/EventRepositoryImpl.kt new file mode 100644 index 0000000..0c59c91 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/repository/EventRepositoryImpl.kt @@ -0,0 +1,64 @@ +package com.diegocayo.organizame.data.repository + +import com.diegocayo.organizame.data.local.dao.EventDao +import com.diegocayo.organizame.data.mapper.toEntity +import com.diegocayo.organizame.data.mapper.toModel +import com.diegocayo.organizame.domain.model.Event +import com.diegocayo.organizame.domain.repository.EventRepository +import com.diegocayo.organizame.domain.repository.SubjectRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import java.util.Calendar +import javax.inject.Inject + +class EventRepositoryImpl @Inject constructor( + private val eventDao: EventDao, + private val subjectRepository: SubjectRepository +) : EventRepository { + + override fun getAllEvents(): Flow> { + return eventDao.getAllEvents().map { entities -> + entities.map { entity -> + val subject = entity.subjectId?.let { id -> + subjectRepository.getSubjectById(id) + } + entity.toModel(subject) + } + } + } + + override fun getEventsByDate(date: Long): Flow> { + val calendar = Calendar.getInstance().apply { + timeInMillis = date + set(Calendar.HOUR_OF_DAY, 0) + set(Calendar.MINUTE, 0) + set(Calendar.SECOND, 0) + set(Calendar.MILLISECOND, 0) + } + val startOfDay = calendar.timeInMillis + + calendar.add(Calendar.DAY_OF_MONTH, 1) + val endOfDay = calendar.timeInMillis + + return eventDao.getEventsByDate(startOfDay, endOfDay).map { entities -> + entities.map { entity -> + val subject = entity.subjectId?.let { id -> + subjectRepository.getSubjectById(id) + } + entity.toModel(subject) + } + } + } + + override suspend fun insertEvent(event: Event): Long { + return eventDao.insertEvent(event.toEntity()) + } + + override suspend fun updateEvent(event: Event) { + eventDao.updateEvent(event.toEntity()) + } + + override suspend fun deleteEvent(event: Event) { + eventDao.deleteEvent(event.toEntity()) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/repository/LoginRepositoryImpl.kt b/app/src/main/java/com/diegocayo/organizame/data/repository/LoginRepositoryImpl.kt new file mode 100644 index 0000000..abb079a --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/repository/LoginRepositoryImpl.kt @@ -0,0 +1,18 @@ +package com.diegocayo.organizame.data.repository + +import com.diegocayo.organizame.data.local.datasource.PreferencesDataSource +import com.diegocayo.organizame.domain.repository.LoginRepository +import javax.inject.Inject + +class LoginRepositoryImpl @Inject constructor( + private val preferencesDataSource: PreferencesDataSource +) : LoginRepository { + + override suspend fun setLoginStatus(isLoggedIn: Boolean) { + preferencesDataSource.setLoginStatus(isLoggedIn) + } + + override suspend fun isLoggedIn(): Boolean { + return preferencesDataSource.isLoggedIn() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/repository/SubjectRepositoryImpl.kt b/app/src/main/java/com/diegocayo/organizame/data/repository/SubjectRepositoryImpl.kt new file mode 100644 index 0000000..3c7b21a --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/repository/SubjectRepositoryImpl.kt @@ -0,0 +1,38 @@ +package com.diegocayo.organizame.data.repository + +import com.diegocayo.organizame.data.local.dao.SubjectDao +import com.diegocayo.organizame.data.mapper.toEntity +import com.diegocayo.organizame.data.mapper.toModel +import com.diegocayo.organizame.domain.model.Subject +import com.diegocayo.organizame.domain.repository.SubjectRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +class SubjectRepositoryImpl @Inject constructor( + private val subjectDao: SubjectDao +) : SubjectRepository { + + override fun getAllSubjects(): Flow> = + subjectDao.getAllSubjects().map { entities -> + entities.map { it.toModel() } + } + + override suspend fun getSubjectById(id: Long): Subject? = + subjectDao.getSubjectById(id)?.toModel() + + override suspend fun insertSubject(subject: Subject): Long = + subjectDao.insertSubject(subject.toEntity()) + + override suspend fun updateSubject(subject: Subject) { + subjectDao.updateSubject(subject.toEntity()) + } + + override suspend fun deleteSubject(subject: Subject) { + subjectDao.deleteSubject(subject.toEntity()) + } + + override suspend fun deleteAllSubjects() { + subjectDao.deleteAllSubjects() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/repository/TaskRepositoryImpl.kt b/app/src/main/java/com/diegocayo/organizame/data/repository/TaskRepositoryImpl.kt new file mode 100644 index 0000000..9ec8c06 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/repository/TaskRepositoryImpl.kt @@ -0,0 +1,75 @@ +package com.diegocayo.organizame.data.repository + +import com.diegocayo.organizame.data.local.dao.TaskDao +import com.diegocayo.organizame.data.local.entity.TaskStatus +import com.diegocayo.organizame.data.mapper.toEntity +import com.diegocayo.organizame.data.mapper.toModel +import com.diegocayo.organizame.domain.model.Task +import com.diegocayo.organizame.domain.repository.SubjectRepository +import com.diegocayo.organizame.domain.repository.TaskRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +class TaskRepositoryImpl @Inject constructor( + private val taskDao: TaskDao, + private val subjectRepository: SubjectRepository +) : TaskRepository { + override fun getAllTasks(): Flow> { + return taskDao.getAllTasks().map { tasks -> + tasks.map { taskEntity -> + val subject = taskEntity.subjectId?.let { id -> + subjectRepository.getSubjectById(id) + } + taskEntity.toModel(subject) + } + } + } + + override fun getPendingTasks(): Flow> { + return taskDao.getPendingTasks().map { tasks -> + tasks.map { taskEntity -> + val subject = taskEntity.subjectId?.let { id -> + subjectRepository.getSubjectById(id) + } + taskEntity.toModel(subject) + } + } + } + + override fun getCompletedTasks(): Flow> { + return taskDao.getCompletedTasks().map { tasks -> + tasks.map { taskEntity -> + val subject = taskEntity.subjectId?.let { id -> + subjectRepository.getSubjectById(id) + } + taskEntity.toModel(subject) + } + } + } + + override suspend fun getTaskById(taskId: Long): Task? { + return taskDao.getTaskById(taskId)?.let { taskEntity -> + val subject = taskEntity.subjectId?.let { id -> + subjectRepository.getSubjectById(id) + } + taskEntity.toModel(subject) + } + } + + override suspend fun insertTask(task: Task): Long { + return taskDao.insertTask(task.toEntity()) + } + + override suspend fun updateTask(task: Task) { + taskDao.updateTask(task.toEntity()) + } + + override suspend fun deleteTask(task: Task) { + taskDao.deleteTask(task.toEntity()) + } + + override suspend fun updateTaskStatus(taskId: Long, status: TaskStatus) { + taskDao.updateTaskStatus(taskId, status.name) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/data/repository/UserRepositoryImpl.kt b/app/src/main/java/com/diegocayo/organizame/data/repository/UserRepositoryImpl.kt new file mode 100644 index 0000000..288737c --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/data/repository/UserRepositoryImpl.kt @@ -0,0 +1,29 @@ +package com.diegocayo.organizame.data.repository + +import com.diegocayo.organizame.data.local.datasource.PreferencesDataSource +import com.diegocayo.organizame.data.mapper.toDomain +import com.diegocayo.organizame.data.mapper.toDto +import com.diegocayo.organizame.domain.model.User +import com.diegocayo.organizame.domain.repository.UserRepository +import javax.inject.Inject + +class UserRepositoryImpl @Inject constructor( + private val preferencesDataSource: PreferencesDataSource +) : UserRepository { + + override suspend fun saveUser(user: User) { + preferencesDataSource.saveUser(user.toDto()) + } + + override suspend fun getUser(): User? { + return preferencesDataSource.getUser()?.toDomain() + } + + override suspend fun updateLoginStatus(isLoggedIn: Boolean) { + preferencesDataSource.setLoginStatus(isLoggedIn) + } + + override suspend fun clearUser() { + preferencesDataSource.clearUser() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/di/DomainModule.kt b/app/src/main/java/com/diegocayo/organizame/domain/di/DomainModule.kt new file mode 100644 index 0000000..a9eb0a8 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/di/DomainModule.kt @@ -0,0 +1,21 @@ +package com.diegocayo.organizame.domain.di + +import com.diegocayo.organizame.domain.utils.DefaultDispatcherProvider +import com.diegocayo.organizame.domain.utils.DispatcherProvider +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + + +@Module +@InstallIn(SingletonComponent::class) +object DomainDI { + + @Provides + @Singleton + fun provideDispatcherProvider(): DispatcherProvider { + return DefaultDispatcherProvider() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/model/Event.kt b/app/src/main/java/com/diegocayo/organizame/domain/model/Event.kt new file mode 100644 index 0000000..e431fa7 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/model/Event.kt @@ -0,0 +1,12 @@ +package com.diegocayo.organizame.domain.model + +data class Event( + val id: Long = 0, + val title: String, + val description: String, + val subject: Subject?, + val date: Long, + val startTime: Long, + val endTime: Long, + val createdAt: Long +) \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/model/Subject.kt b/app/src/main/java/com/diegocayo/organizame/domain/model/Subject.kt new file mode 100644 index 0000000..2333c61 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/model/Subject.kt @@ -0,0 +1,8 @@ +package com.diegocayo.organizame.domain.model + +data class Subject( + val id: Long = 0, + val name: String, + val abbreviation: String, + val color: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/model/Task.kt b/app/src/main/java/com/diegocayo/organizame/domain/model/Task.kt new file mode 100644 index 0000000..28ea782 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/model/Task.kt @@ -0,0 +1,15 @@ +package com.diegocayo.organizame.domain.model + +import com.diegocayo.organizame.data.local.entity.TaskPriority +import com.diegocayo.organizame.data.local.entity.TaskStatus + +data class Task( + val id: Long = 0, + val title: String, + val description: String, + val subject: Subject?, + val priority: TaskPriority, + val status: TaskStatus, + val scheduledDate: Long, + val createdAt: Long +) \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/model/User.kt b/app/src/main/java/com/diegocayo/organizame/domain/model/User.kt new file mode 100644 index 0000000..edbc1ae --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/model/User.kt @@ -0,0 +1,7 @@ +package com.diegocayo.organizame.domain.model + +data class User( + val name: String, + val surname: String, + val birthdate: String +) \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/repository/EventRepository.kt b/app/src/main/java/com/diegocayo/organizame/domain/repository/EventRepository.kt new file mode 100644 index 0000000..325fc37 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/repository/EventRepository.kt @@ -0,0 +1,12 @@ +package com.diegocayo.organizame.domain.repository + +import com.diegocayo.organizame.domain.model.Event +import kotlinx.coroutines.flow.Flow + +interface EventRepository { + fun getAllEvents(): Flow> + fun getEventsByDate(date: Long): Flow> + suspend fun insertEvent(event: Event): Long + suspend fun updateEvent(event: Event) + suspend fun deleteEvent(event: Event) +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/repository/LoginRepository.kt b/app/src/main/java/com/diegocayo/organizame/domain/repository/LoginRepository.kt new file mode 100644 index 0000000..4b85ff5 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/repository/LoginRepository.kt @@ -0,0 +1,6 @@ +package com.diegocayo.organizame.domain.repository + +interface LoginRepository { + suspend fun setLoginStatus(isLoggedIn: Boolean) + suspend fun isLoggedIn(): Boolean +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/repository/SubjectRepository.kt b/app/src/main/java/com/diegocayo/organizame/domain/repository/SubjectRepository.kt new file mode 100644 index 0000000..453c2d1 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/repository/SubjectRepository.kt @@ -0,0 +1,13 @@ +package com.diegocayo.organizame.domain.repository + +import com.diegocayo.organizame.domain.model.Subject +import kotlinx.coroutines.flow.Flow + +interface SubjectRepository { + fun getAllSubjects(): Flow> + suspend fun getSubjectById(id: Long): Subject? + suspend fun insertSubject(subject: Subject): Long + suspend fun updateSubject(subject: Subject) + suspend fun deleteSubject(subject: Subject) + suspend fun deleteAllSubjects() +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/repository/TaskRepository.kt b/app/src/main/java/com/diegocayo/organizame/domain/repository/TaskRepository.kt new file mode 100644 index 0000000..7a3c8e6 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/repository/TaskRepository.kt @@ -0,0 +1,16 @@ +package com.diegocayo.organizame.domain.repository + +import com.diegocayo.organizame.data.local.entity.TaskStatus +import com.diegocayo.organizame.domain.model.Task +import kotlinx.coroutines.flow.Flow + +interface TaskRepository { + fun getAllTasks(): Flow> + fun getPendingTasks(): Flow> + fun getCompletedTasks(): Flow> + suspend fun getTaskById(taskId: Long): Task? + suspend fun insertTask(task: Task): Long + suspend fun updateTask(task: Task) + suspend fun deleteTask(task: Task) + suspend fun updateTaskStatus(taskId: Long, status: TaskStatus) +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/repository/UserRepository.kt b/app/src/main/java/com/diegocayo/organizame/domain/repository/UserRepository.kt new file mode 100644 index 0000000..7b4c189 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/repository/UserRepository.kt @@ -0,0 +1,10 @@ +package com.diegocayo.organizame.domain.repository + +import com.diegocayo.organizame.domain.model.User + +interface UserRepository { + suspend fun saveUser(user: User) + suspend fun getUser(): User? + suspend fun updateLoginStatus(isLoggedIn: Boolean) + suspend fun clearUser() +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/usecase/DeleteSubjectUseCase.kt b/app/src/main/java/com/diegocayo/organizame/domain/usecase/DeleteSubjectUseCase.kt new file mode 100644 index 0000000..40a868e --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/usecase/DeleteSubjectUseCase.kt @@ -0,0 +1,11 @@ +package com.diegocayo.organizame.domain.usecase + +import com.diegocayo.organizame.domain.model.Subject +import com.diegocayo.organizame.domain.repository.SubjectRepository +import javax.inject.Inject + +class DeleteSubjectUseCase @Inject constructor( + private val repository: SubjectRepository +) { + suspend operator fun invoke(subject: Subject) = repository.deleteSubject(subject) +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/usecase/GetAllSubjectsUseCase.kt b/app/src/main/java/com/diegocayo/organizame/domain/usecase/GetAllSubjectsUseCase.kt new file mode 100644 index 0000000..3505822 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/usecase/GetAllSubjectsUseCase.kt @@ -0,0 +1,12 @@ +package com.diegocayo.organizame.domain.usecase + +import com.diegocayo.organizame.domain.model.Subject +import com.diegocayo.organizame.domain.repository.SubjectRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetAllSubjectsUseCase @Inject constructor( + private val repository: SubjectRepository +) { + operator fun invoke(): Flow> = repository.getAllSubjects() +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/usecase/GetUserUseCase.kt b/app/src/main/java/com/diegocayo/organizame/domain/usecase/GetUserUseCase.kt new file mode 100644 index 0000000..760a375 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/usecase/GetUserUseCase.kt @@ -0,0 +1,19 @@ +package com.diegocayo.organizame.domain.usecase + +import com.diegocayo.organizame.domain.model.User +import com.diegocayo.organizame.domain.repository.UserRepository +import com.diegocayo.organizame.domain.utils.DispatcherProvider +import com.diegocayo.organizame.domain.utils.FlowUseCase +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class GetUserUseCase @Inject constructor( + private val repository: UserRepository, + dispatcherProvider: DispatcherProvider +) : FlowUseCase(dispatcherProvider) { + + override fun prepareFlow(input: Unit) = flow { + val user = repository.getUser() + emit(user) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/usecase/IsLoggedInUseCase.kt b/app/src/main/java/com/diegocayo/organizame/domain/usecase/IsLoggedInUseCase.kt new file mode 100644 index 0000000..bc2b4a9 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/usecase/IsLoggedInUseCase.kt @@ -0,0 +1,17 @@ +package com.diegocayo.organizame.domain.usecase + +import com.diegocayo.organizame.domain.repository.LoginRepository +import com.diegocayo.organizame.domain.utils.DispatcherProvider +import com.diegocayo.organizame.domain.utils.FlowUseCase +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class IsLoggedInUseCase @Inject constructor( + private val repository: LoginRepository, + dispatcherProvider: DispatcherProvider +) : FlowUseCase(dispatcherProvider) { + + override fun prepareFlow(input: Unit) = flow { + emit(repository.isLoggedIn()) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/usecase/SaveSubjectUseCase.kt b/app/src/main/java/com/diegocayo/organizame/domain/usecase/SaveSubjectUseCase.kt new file mode 100644 index 0000000..48d518c --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/usecase/SaveSubjectUseCase.kt @@ -0,0 +1,11 @@ +package com.diegocayo.organizame.domain.usecase + +import com.diegocayo.organizame.domain.model.Subject +import com.diegocayo.organizame.domain.repository.SubjectRepository +import javax.inject.Inject + +class SaveSubjectUseCase @Inject constructor( + private val repository: SubjectRepository +) { + suspend operator fun invoke(subject: Subject): Long = repository.insertSubject(subject) +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/usecase/SaveUserUseCase.kt b/app/src/main/java/com/diegocayo/organizame/domain/usecase/SaveUserUseCase.kt new file mode 100644 index 0000000..f29661c --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/usecase/SaveUserUseCase.kt @@ -0,0 +1,19 @@ +package com.diegocayo.organizame.domain.usecase + +import com.diegocayo.organizame.domain.model.User +import com.diegocayo.organizame.domain.repository.UserRepository +import com.diegocayo.organizame.domain.utils.DispatcherProvider +import com.diegocayo.organizame.domain.utils.FlowUseCase +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class SaveUserUseCase @Inject constructor( + private val repository: UserRepository, + dispatcherProvider: DispatcherProvider +) : FlowUseCase(dispatcherProvider) { + + override fun prepareFlow(input: User) = flow { + repository.saveUser(input) + emit(Unit) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/usecase/SetLoginStatusUseCase.kt b/app/src/main/java/com/diegocayo/organizame/domain/usecase/SetLoginStatusUseCase.kt new file mode 100644 index 0000000..cf3b710 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/usecase/SetLoginStatusUseCase.kt @@ -0,0 +1,18 @@ +package com.diegocayo.organizame.domain.usecase + +import com.diegocayo.organizame.domain.repository.LoginRepository +import com.diegocayo.organizame.domain.utils.DispatcherProvider +import com.diegocayo.organizame.domain.utils.FlowUseCase +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class SetLoginStatusUseCase @Inject constructor( + private val repository: LoginRepository, + dispatcherProvider: DispatcherProvider +) : FlowUseCase(dispatcherProvider) { + + override fun prepareFlow(input: Boolean) = flow { + repository.setLoginStatus(input) + emit(Unit) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/usecase/UpdateLoginStatusUseCase.kt b/app/src/main/java/com/diegocayo/organizame/domain/usecase/UpdateLoginStatusUseCase.kt new file mode 100644 index 0000000..9392b5c --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/usecase/UpdateLoginStatusUseCase.kt @@ -0,0 +1,18 @@ +package com.diegocayo.organizame.domain.usecase + +import com.diegocayo.organizame.domain.repository.LoginRepository +import com.diegocayo.organizame.domain.utils.DispatcherProvider +import com.diegocayo.organizame.domain.utils.FlowUseCase +import kotlinx.coroutines.flow.flow +import javax.inject.Inject + +class UpdateLoginStatusUseCase @Inject constructor( + private val repository: LoginRepository, + dispatcherProvider: DispatcherProvider +) : FlowUseCase(dispatcherProvider) { + + override fun prepareFlow(input: Boolean) = flow { + repository.setLoginStatus(input) + emit(Unit) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/utils/DispatcherProvider.kt b/app/src/main/java/com/diegocayo/organizame/domain/utils/DispatcherProvider.kt new file mode 100644 index 0000000..7b6429d --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/utils/DispatcherProvider.kt @@ -0,0 +1,15 @@ +package com.diegocayo.organizame.domain.utils + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import javax.inject.Inject + +interface DispatcherProvider { + + fun main(): CoroutineDispatcher = Dispatchers.Main + fun default(): CoroutineDispatcher = Dispatchers.Default + fun io(): CoroutineDispatcher = Dispatchers.IO + fun unconfined(): CoroutineDispatcher = Dispatchers.Unconfined +} + +class DefaultDispatcherProvider @Inject constructor() : DispatcherProvider \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/domain/utils/FlowUseCase.kt b/app/src/main/java/com/diegocayo/organizame/domain/utils/FlowUseCase.kt new file mode 100644 index 0000000..3e47777 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/domain/utils/FlowUseCase.kt @@ -0,0 +1,32 @@ +package com.diegocayo.organizame.domain.utils + +import androidx.annotation.CheckResult +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import kotlin.coroutines.CoroutineContext + +abstract class FlowUseCase(protected open val dispatcherProvider: DispatcherProvider) { + + protected open fun dispatcher(): CoroutineContext = dispatcherProvider.io() + + @CheckResult + fun prepare(input: T) = prepareFlow(input).flowOn(dispatcher()) + + + protected abstract fun prepareFlow(input: T): Flow +} + +abstract class GenericFlowUseCase(protected open val dispatcherProvider: DispatcherProvider) { + + protected open fun dispatcher(): CoroutineContext = dispatcherProvider.io() + + @CheckResult + fun prepare(input: T, klass: Class) = prepareFlow(input, klass).flowOn(dispatcher()) + + @CheckResult + inline fun prepare(input: T) = prepare(input, R::class.java) + + + abstract fun prepareFlow(input: T, klass: Class): Flow +} diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/components/ColorPicker.kt b/app/src/main/java/com/diegocayo/organizame/presentation/components/ColorPicker.kt new file mode 100644 index 0000000..43bf75b --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/components/ColorPicker.kt @@ -0,0 +1,101 @@ +package com.diegocayo.organizame.presentation.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +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.unit.dp + +@Composable +fun ColorPicker( + selectedColor: Int, + onColorSelected: (Int) -> Unit, + modifier: Modifier = Modifier +) { + val colors = listOf( + 0xFF1976D2.toInt(), // Azul + 0xFF388E3C.toInt(), // Verde + 0xFFF57C00.toInt(), // Naranja + 0xFFD32F2F.toInt(), // Rojo + 0xFF7B1FA2.toInt(), // Morado + 0xFF00796B.toInt(), // Verde azulado + 0xFFE64A19.toInt(), // Naranja oscuro + 0xFF5D4037.toInt(), // Marrón + 0xFFE91E63.toInt(), // Rosa + 0xFF9C27B0.toInt(), // Púrpura + 0xFF009688.toInt(), // Turquesa + 0xFFFFEB3B.toInt(), // Amarillo + 0xFF795548.toInt(), // Marrón claro + 0xFF607D8B.toInt(), // Gris azulado + 0xFF3F51B5.toInt(), // Índigo + 0xFF4CAF50.toInt() // Verde lima + ) + + Column( + modifier = modifier.fillMaxWidth(), + horizontalAlignment = Alignment.Start + ) { + Text( + text = "Color", + style = MaterialTheme.typography.bodyLarge, + modifier = Modifier.padding(horizontal = 16.dp) + ) + + Spacer(modifier = Modifier.height(8.dp)) + + LazyRow( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 8.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + items(colors) { color -> + ColorCircle( + color = Color(color), + selected = color == selectedColor, + onClick = { onColorSelected(color) } + ) + } + } + } +} + +@Composable +private fun ColorCircle( + color: Color, + selected: Boolean, + onClick: () -> Unit +) { + Box( + modifier = Modifier + .size(40.dp) + .clip(CircleShape) + .background(color) + .then( + if (selected) { + Modifier.border(2.dp, MaterialTheme.colorScheme.primary, CircleShape) + } else { + Modifier + } + ) + .clickable(onClick = onClick) + .padding(4.dp) + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/components/DayOfWeekPicker.kt b/app/src/main/java/com/diegocayo/organizame/presentation/components/DayOfWeekPicker.kt new file mode 100644 index 0000000..355eb5c --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/components/DayOfWeekPicker.kt @@ -0,0 +1,49 @@ +package com.diegocayo.organizame.presentation.components + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SegmentedButton +import androidx.compose.material3.SingleChoiceSegmentedButtonRow +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DayOfWeekPicker( + selectedDay: Int, + onDaySelected: (Int) -> Unit, + modifier: Modifier = Modifier +) { + val days = listOf("L", "M", "X", "J", "V", "S", "D") + + Column( + modifier = modifier.fillMaxWidth(), + horizontalAlignment = Alignment.Start + ) { + Text( + text = "Día de la semana", + style = MaterialTheme.typography.bodyLarge + ) + + Spacer(modifier = Modifier.height(8.dp)) + + SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) { + days.forEachIndexed { index, label -> + SegmentedButton( + selected = selectedDay == index + 1, + shape = MaterialTheme.shapes.small, + onClick = { onDaySelected(index + 1) } + ) { + Text(label) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/components/TimePicker.kt b/app/src/main/java/com/diegocayo/organizame/presentation/components/TimePicker.kt new file mode 100644 index 0000000..3b9ad0e --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/components/TimePicker.kt @@ -0,0 +1,65 @@ +package com.diegocayo.organizame.presentation.components + +import android.app.TimePickerDialog +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp +import java.time.LocalTime +import java.time.format.DateTimeFormatter + +@Composable +fun TimePicker( + selectedTime: String, + onTimeSelected: (String) -> Unit, + modifier: Modifier = Modifier +) { + val context = LocalContext.current + val formatter = DateTimeFormatter.ofPattern("HH:mm") + val time = try { + LocalTime.parse(selectedTime, formatter) + } catch (e: Exception) { + LocalTime.of(8, 0) + } + + val timePickerDialog = TimePickerDialog( + context, + { _, hour, minute -> + val newTime = LocalTime.of(hour, minute) + onTimeSelected(newTime.format(formatter)) + }, + time.hour, + time.minute, + true + ) + + Column( + modifier = modifier.fillMaxWidth(), + horizontalAlignment = Alignment.Start + ) { + Text( + text = "Hora", + style = MaterialTheme.typography.bodyLarge + ) + + Spacer(modifier = Modifier.height(8.dp)) + + OutlinedTextField( + value = selectedTime, + onValueChange = { }, + readOnly = true, + modifier = Modifier + .fillMaxWidth() + .clickable { timePickerDialog.show() } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/MainActivity.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/MainActivity.kt new file mode 100644 index 0000000..599031e --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/MainActivity.kt @@ -0,0 +1,57 @@ +package com.diegocayo.organizame.presentation.features + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.activity.viewModels +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.diegocayo.organizame.presentation.navigation.RootNavHost +import com.diegocayo.organizame.presentation.theme.OrganizaMeTheme +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class MainActivity : ComponentActivity() { + private val viewModel: MainViewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContent { + OrganizaMeTheme { + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + MyApp(viewModel = viewModel) + } + } + } + } +} + +@Composable +fun MyApp(viewModel: MainViewModel) { + when { + viewModel.isLoading -> { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator() + } + } + + else -> { + RootNavHost(isAuthenticated = viewModel.isLoggedIn) + } + } +} + diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/MainViewModel.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/MainViewModel.kt new file mode 100644 index 0000000..eaaa42c --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/MainViewModel.kt @@ -0,0 +1,45 @@ +package com.diegocayo.organizame.presentation.features + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.diegocayo.organizame.domain.usecase.IsLoggedInUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import javax.inject.Inject + +@HiltViewModel +class MainViewModel @Inject constructor( + private val isLoggedInUseCase: IsLoggedInUseCase +) : ViewModel() { + + var isLoading by mutableStateOf(true) + private set + + var isLoggedIn by mutableStateOf(false) + private set + + var error by mutableStateOf(null) + private set + + init { + checkLoginStatus() + } + + private fun checkLoginStatus() { + isLoggedInUseCase.prepare(Unit) + .onEach { loggedIn -> + isLoggedIn = loggedIn + isLoading = false + } + .catch { exception -> + error = exception.message + isLoading = false + } + .launchIn(viewModelScope) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/MocksScreen.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/MocksScreen.kt new file mode 100644 index 0000000..b1534aa --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/MocksScreen.kt @@ -0,0 +1,20 @@ +package com.diegocayo.organizame.presentation.features + +import androidx.compose.runtime.Composable + +@Composable +fun TasksScreen() { + +} + +@Composable +fun EventsScreen() { + +} + +@Composable +fun SubjectsScreen() { + +} + + diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/create/CreateEventScreen.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/create/CreateEventScreen.kt new file mode 100644 index 0000000..fc2a45b --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/create/CreateEventScreen.kt @@ -0,0 +1,305 @@ +package com.diegocayo.organizame.presentation.features.main.events.create + +import android.app.DatePickerDialog +import android.app.TimePickerDialog +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.CalendarToday +import androidx.compose.material.icons.filled.Schedule +import androidx.compose.material3.Button +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExposedDropdownMenuBox +import androidx.compose.material3.ExposedDropdownMenuDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import com.diegocayo.organizame.R +import com.diegocayo.organizame.domain.model.Subject +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date +import java.util.Locale + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun CreateEventScreen( + onNavigateBack: () -> Unit, + viewModel: CreateEventViewModel = hiltViewModel() +) { + val state by viewModel.state.collectAsState() + val context = LocalContext.current + + LaunchedEffect(state.isEventCreated) { + if (state.isEventCreated) { + onNavigateBack() + } + } + + if (state.showDatePicker) { + val calendar = Calendar.getInstance().apply { + timeInMillis = state.date + } + + DatePickerDialog( + context, + { _, year, month, dayOfMonth -> + calendar.set(year, month, dayOfMonth) + viewModel.onEvent(CreateEventEvent.OnDateSelect(calendar.timeInMillis)) + }, + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.get(Calendar.DAY_OF_MONTH) + ).show() + + viewModel.onEvent(CreateEventEvent.OnHideDatePicker) + } + + if (state.showStartTimePicker) { + val calendar = Calendar.getInstance().apply { + timeInMillis = state.startTime + } + + TimePickerDialog( + context, + { _, hourOfDay, minute -> + calendar.set(Calendar.HOUR_OF_DAY, hourOfDay) + calendar.set(Calendar.MINUTE, minute) + viewModel.onEvent(CreateEventEvent.OnStartTimeSelect(calendar.timeInMillis)) + }, + calendar.get(Calendar.HOUR_OF_DAY), + calendar.get(Calendar.MINUTE), + true + ).show() + + viewModel.onEvent(CreateEventEvent.OnHideStartTimePicker) + } + + if (state.showEndTimePicker) { + val calendar = Calendar.getInstance().apply { + timeInMillis = state.endTime + } + + TimePickerDialog( + context, + { _, hourOfDay, minute -> + calendar.set(Calendar.HOUR_OF_DAY, hourOfDay) + calendar.set(Calendar.MINUTE, minute) + viewModel.onEvent(CreateEventEvent.OnEndTimeSelect(calendar.timeInMillis)) + }, + calendar.get(Calendar.HOUR_OF_DAY), + calendar.get(Calendar.MINUTE), + true + ).show() + + viewModel.onEvent(CreateEventEvent.OnHideEndTimePicker) + } + + Scaffold( + topBar = { + TopAppBar( + title = { Text(stringResource(R.string.e_c_view_new_event)) }, + navigationIcon = { + IconButton(onClick = onNavigateBack) { + Icon( + Icons.Default.ArrowBack, + contentDescription = stringResource(R.string.text_back) + ) + } + } + ) + } + ) { padding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(padding) + .padding(16.dp) + .verticalScroll(rememberScrollState()) + ) { + OutlinedTextField( + value = state.title, + onValueChange = { viewModel.onEvent(CreateEventEvent.OnTitleChange(it)) }, + label = { Text(stringResource(R.string.text_title)) }, + modifier = Modifier.fillMaxWidth(), + isError = state.error?.contains("título") == true + ) + + Spacer(modifier = Modifier.height(16.dp)) + + OutlinedTextField( + value = state.description, + onValueChange = { viewModel.onEvent(CreateEventEvent.OnDescriptionChange(it)) }, + label = { Text(stringResource(R.string.text_description)) }, + modifier = Modifier.fillMaxWidth(), + minLines = 3 + ) + + Spacer(modifier = Modifier.height(16.dp)) + + val dateFormat = SimpleDateFormat("dd 'de' MMMM, yyyy", Locale("es", "ES")) + OutlinedTextField( + value = dateFormat.format(Date(state.date)), + onValueChange = { }, + readOnly = true, + label = { Text(stringResource(R.string.e_c_view_date)) }, + trailingIcon = { + Icon( + Icons.Default.CalendarToday, + contentDescription = stringResource(R.string.e_c_view_date), + modifier = Modifier.clickable { + viewModel.onEvent(CreateEventEvent.OnShowDatePicker) + } + ) + }, + modifier = Modifier.fillMaxWidth() + ) + + Spacer(modifier = Modifier.height(16.dp)) + + val timeFormat = SimpleDateFormat("HH:mm", Locale("es", "ES")) + OutlinedTextField( + value = timeFormat.format(Date(state.startTime)), + onValueChange = { }, + readOnly = true, + label = { Text(stringResource(R.string.e_c_view_start_time)) }, + trailingIcon = { + Icon( + Icons.Default.Schedule, + contentDescription = stringResource(R.string.e_c_view_start_time), + modifier = Modifier.clickable { + viewModel.onEvent(CreateEventEvent.OnShowStartTimePicker) + } + ) + }, + modifier = Modifier.fillMaxWidth() + ) + + Spacer(modifier = Modifier.height(16.dp)) + + OutlinedTextField( + value = timeFormat.format(Date(state.endTime)), + onValueChange = { }, + readOnly = true, + label = { Text(stringResource(R.string.e_c_view_end_time)) }, + trailingIcon = { + Icon( + Icons.Default.Schedule, + contentDescription = stringResource(R.string.e_c_view_end_time), + modifier = Modifier.clickable { + viewModel.onEvent(CreateEventEvent.OnShowEndTimePicker) + } + ) + }, + modifier = Modifier.fillMaxWidth() + ) + + Spacer(modifier = Modifier.height(16.dp)) + + SubjectDropdown( + selectedSubject = state.selectedSubject, + subjects = state.subjects, + onSubjectSelected = { viewModel.onEvent(CreateEventEvent.OnSubjectSelect(it)) } + ) + + Spacer(modifier = Modifier.height(24.dp)) + + Button( + onClick = { viewModel.onEvent(CreateEventEvent.OnCreateEvent) }, + modifier = Modifier.fillMaxWidth(), + enabled = !state.isLoading && state.isFormValid + ) { + if (state.isLoading) { + CircularProgressIndicator( + modifier = Modifier.padding(end = 8.dp), + strokeWidth = 2.dp + ) + } + Text(stringResource(R.string.e_c_view_create_event)) + } + + state.error?.let { error -> + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = error, + color = MaterialTheme.colorScheme.error, + style = MaterialTheme.typography.bodyMedium + ) + } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SubjectDropdown( + selectedSubject: Subject?, + subjects: List, + onSubjectSelected: (Subject?) -> Unit +) { + var expanded by remember { mutableStateOf(false) } + + ExposedDropdownMenuBox( + expanded = expanded, + onExpandedChange = { expanded = it } + ) { + OutlinedTextField( + value = selectedSubject?.name ?: stringResource(R.string.text_no_subject), + onValueChange = {}, + readOnly = true, + trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, + modifier = Modifier + .fillMaxWidth() + .menuAnchor(), + label = { Text(stringResource(R.string.subjects)) } + ) + + ExposedDropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false } + ) { + DropdownMenuItem( + text = { Text("Sin asignatura") }, + onClick = { + onSubjectSelected(null) + expanded = false + } + ) + subjects.forEach { subject -> + DropdownMenuItem( + text = { Text(subject.name) }, + onClick = { + onSubjectSelected(subject) + expanded = false + } + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/create/CreateEventState.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/create/CreateEventState.kt new file mode 100644 index 0000000..a526adf --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/create/CreateEventState.kt @@ -0,0 +1,36 @@ +package com.diegocayo.organizame.presentation.features.main.events.create + +import com.diegocayo.organizame.domain.model.Subject + +data class CreateEventState( + val title: String = "", + val description: String = "", + val selectedSubject: Subject? = null, + val date: Long = System.currentTimeMillis(), + val startTime: Long = System.currentTimeMillis(), + val endTime: Long = System.currentTimeMillis() + 3600000, + val subjects: List = emptyList(), + val isLoading: Boolean = false, + val error: String? = null, + val isEventCreated: Boolean = false, + val showDatePicker: Boolean = false, + val showStartTimePicker: Boolean = false, + val showEndTimePicker: Boolean = false, + val isFormValid: Boolean = false +) + +sealed class CreateEventEvent { + data class OnTitleChange(val title: String) : CreateEventEvent() + data class OnDescriptionChange(val description: String) : CreateEventEvent() + data class OnSubjectSelect(val subject: Subject?) : CreateEventEvent() + data class OnDateSelect(val timestamp: Long) : CreateEventEvent() + data class OnStartTimeSelect(val timestamp: Long) : CreateEventEvent() + data class OnEndTimeSelect(val timestamp: Long) : CreateEventEvent() + data object OnShowDatePicker : CreateEventEvent() + data object OnShowStartTimePicker : CreateEventEvent() + data object OnShowEndTimePicker : CreateEventEvent() + data object OnHideDatePicker : CreateEventEvent() + data object OnHideStartTimePicker : CreateEventEvent() + data object OnHideEndTimePicker : CreateEventEvent() + data object OnCreateEvent : CreateEventEvent() +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/create/CreateEventViewModel.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/create/CreateEventViewModel.kt new file mode 100644 index 0000000..8e5a0f4 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/create/CreateEventViewModel.kt @@ -0,0 +1,158 @@ +package com.diegocayo.organizame.presentation.features.main.events.create + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.diegocayo.organizame.domain.model.Event +import com.diegocayo.organizame.domain.repository.EventRepository +import com.diegocayo.organizame.domain.repository.SubjectRepository +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 + +@HiltViewModel +class CreateEventViewModel @Inject constructor( + private val eventRepository: EventRepository, + private val subjectRepository: SubjectRepository +) : ViewModel() { + + private val _state = MutableStateFlow(CreateEventState()) + val state: StateFlow = _state.asStateFlow() + + init { + loadSubjects() + } + + private fun loadSubjects() { + viewModelScope.launch { + try { + subjectRepository.getAllSubjects().collect { subjects -> + _state.value = _state.value.copy(subjects = subjects) + } + } catch (e: Exception) { + _state.value = _state.value.copy(error = e.message) + } + } + } + + fun onEvent(event: CreateEventEvent) { + when (event) { + is CreateEventEvent.OnTitleChange -> { + _state.value = _state.value.copy(title = event.title) + validateForm() + } + + is CreateEventEvent.OnDescriptionChange -> { + _state.value = _state.value.copy(description = event.description) + validateForm() + } + + is CreateEventEvent.OnSubjectSelect -> { + _state.value = _state.value.copy(selectedSubject = event.subject) + validateForm() + } + + is CreateEventEvent.OnDateSelect -> { + _state.value = _state.value.copy( + date = event.timestamp, + showDatePicker = false + ) + validateForm() + } + + is CreateEventEvent.OnStartTimeSelect -> { + _state.value = _state.value.copy( + startTime = event.timestamp, + showStartTimePicker = false + ) + validateForm() + } + + is CreateEventEvent.OnEndTimeSelect -> { + _state.value = _state.value.copy( + endTime = event.timestamp, + showEndTimePicker = false + ) + validateForm() + } + + is CreateEventEvent.OnShowDatePicker -> { + _state.value = _state.value.copy(showDatePicker = true) + } + + is CreateEventEvent.OnShowStartTimePicker -> { + _state.value = _state.value.copy(showStartTimePicker = true) + } + + is CreateEventEvent.OnShowEndTimePicker -> { + _state.value = _state.value.copy(showEndTimePicker = true) + } + + is CreateEventEvent.OnHideDatePicker -> { + _state.value = _state.value.copy(showDatePicker = false) + } + + is CreateEventEvent.OnHideStartTimePicker -> { + _state.value = _state.value.copy(showStartTimePicker = false) + } + + is CreateEventEvent.OnHideEndTimePicker -> { + _state.value = _state.value.copy(showEndTimePicker = false) + } + + is CreateEventEvent.OnCreateEvent -> createEvent() + } + } + + private fun validateForm() { + val currentState = _state.value + val isValid = currentState.title.isNotBlank() && + currentState.description.isNotBlank() && + currentState.startTime < currentState.endTime + + _state.value = currentState.copy(isFormValid = isValid) + } + + private fun createEvent() { + val currentState = _state.value + + if (!currentState.isFormValid) { + _state.value = + currentState.copy(error = "Por favor, complete todos los campos requeridos") + return + } + + if (currentState.startTime >= currentState.endTime) { + _state.value = + currentState.copy(error = "La hora de inicio debe ser anterior a la hora de fin") + return + } + + viewModelScope.launch { + _state.value = currentState.copy(isLoading = true) + try { + val event = Event( + title = currentState.title, + description = currentState.description, + subject = currentState.selectedSubject, + date = currentState.date, + startTime = currentState.startTime, + endTime = currentState.endTime, + createdAt = System.currentTimeMillis() + ) + eventRepository.insertEvent(event) + _state.value = currentState.copy( + isLoading = false, + isEventCreated = true + ) + } catch (e: Exception) { + _state.value = currentState.copy( + isLoading = false, + error = e.message + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/list/EventsListScreen.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/list/EventsListScreen.kt new file mode 100644 index 0000000..686a8bc --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/list/EventsListScreen.kt @@ -0,0 +1,420 @@ +package com.diegocayo.organizame.presentation.features.main.events.list + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.Delete +import androidx.compose.material.icons.filled.KeyboardArrowLeft +import androidx.compose.material.icons.filled.KeyboardArrowRight +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +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.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavController +import com.diegocayo.organizame.domain.model.Event +import com.diegocayo.organizame.presentation.navigation.AppScreen +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date +import java.util.Locale + +@Composable +fun EventsListScreen( + navController: NavController, + viewModel: EventsListViewModel = hiltViewModel() +) { + val state by viewModel.state.collectAsState() + var selectedEvent by remember { mutableStateOf(null) } + + Scaffold( + floatingActionButton = { + FloatingActionButton( + onClick = { navController.navigate(AppScreen.Main.Events.Create.route) } + ) { + Icon(Icons.Default.Add, contentDescription = "Crear evento") + } + } + ) { padding -> + Box( + modifier = Modifier + .fillMaxSize() + .padding(padding) + ) { + if (state.isLoading) { + CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) + } else { + Column( + modifier = Modifier + .fillMaxSize() + .padding(16.dp) + ) { + CalendarView( + selectedDate = state.selectedDate, + onDateSelected = { date -> viewModel.onEvent(EventsListEvent.ChangeDate(date)) } + ) + + Spacer(modifier = Modifier.height(16.dp)) + + LazyColumn( + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + items(state.events) { event -> + EventCard( + event = event, + onClick = { selectedEvent = event } + ) + } + } + } + } + } + } + + selectedEvent?.let { event -> + EventDetailDialog( + event = event, + onDismiss = { selectedEvent = null }, + onDelete = { + viewModel.onEvent(EventsListEvent.DeleteEvent(event)) + selectedEvent = null + } + ) + } +} + +@Composable +fun CalendarView( + selectedDate: Long, + onDateSelected: (Long) -> Unit +) { + val calendar = Calendar.getInstance() + calendar.timeInMillis = selectedDate + + val selectedDay = calendar.get(Calendar.DAY_OF_MONTH) + val currentMonth = calendar.get(Calendar.MONTH) + val currentYear = calendar.get(Calendar.YEAR) + val daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH) + + val monthFormat = SimpleDateFormat("MMMM", Locale("es", "ES")) + + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surfaceVariant + ) + ) { + Column(modifier = Modifier.padding(16.dp)) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + IconButton(onClick = { + calendar.add(Calendar.MONTH, -1) + onDateSelected(calendar.timeInMillis) + }) { + Icon(Icons.Default.KeyboardArrowLeft, "Mes anterior") + } + + Text( + text = "${ + monthFormat.format(calendar.time).replaceFirstChar { it.uppercase() } + } ${calendar.get(Calendar.YEAR)}", + style = MaterialTheme.typography.titleLarge + ) + + IconButton(onClick = { + calendar.add(Calendar.MONTH, 1) + onDateSelected(calendar.timeInMillis) + }) { + Icon(Icons.Default.KeyboardArrowRight, "Mes siguiente") + } + } + + Spacer(modifier = Modifier.height(16.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + listOf("D", "L", "M", "X", "J", "V", "S").forEach { day -> + Text( + text = day, + modifier = Modifier.weight(1f), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.bodyMedium + ) + } + } + + Spacer(modifier = Modifier.height(8.dp)) + + val firstDayOfMonth = calendar.apply { + set(Calendar.DAY_OF_MONTH, 1) + }.get(Calendar.DAY_OF_WEEK) - 1 + + val days = List(firstDayOfMonth) { "" } + List(daysInMonth) { (it + 1).toString() } + + LazyVerticalGrid( + columns = GridCells.Fixed(7), + modifier = Modifier.height(280.dp), // Aumentado la altura + userScrollEnabled = false // Deshabilitado el scroll + ) { + items(days) { day -> + val isSelected = day.isNotEmpty() && day.toIntOrNull() == selectedDay + + Box( + modifier = Modifier + .aspectRatio(1f) + .padding(4.dp) // Aumentado el padding + .then( + if (day.isNotEmpty()) { + Modifier.clickable { + calendar.set(Calendar.DAY_OF_MONTH, day.toInt()) + onDateSelected(calendar.timeInMillis) + } + } else Modifier + ) + .then( + if (isSelected) { + Modifier + .background( + MaterialTheme.colorScheme.primary, + CircleShape + ) + } else Modifier + ), + contentAlignment = Alignment.Center + ) { + if (day.isNotEmpty()) { + Text( + text = day, + color = if (isSelected) Color.White else Color.Unspecified, + style = MaterialTheme.typography.bodyMedium, + fontWeight = if (isSelected) FontWeight.Bold else FontWeight.Normal, + modifier = Modifier.padding(8.dp) // Añadido padding al texto + ) + } + } + } + } + } + } +} + +@Composable +fun EventCard( + event: Event, + onClick: () -> Unit +) { + val timeFormat = SimpleDateFormat("HH:mm", Locale("es", "ES")) + + Card( + modifier = Modifier + .fillMaxWidth() + .clickable(onClick = onClick), + colors = CardDefaults.cardColors( + containerColor = event.subject?.let { Color(it.color) } + ?: MaterialTheme.colorScheme.surfaceVariant + ), + shape = RoundedCornerShape(12.dp) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Column(modifier = Modifier.weight(1f)) { + Text( + text = event.title, + style = MaterialTheme.typography.titleMedium, + color = Color.White, + fontWeight = FontWeight.Bold + ) + + Text( + text = "${timeFormat.format(Date(event.startTime))} - ${ + timeFormat.format( + Date( + event.endTime + ) + ) + }", + style = MaterialTheme.typography.bodyMedium, + color = Color.White.copy(alpha = 0.8f) + ) + } + + event.subject?.let { + Box( + modifier = Modifier + .size(40.dp) + .background(Color.White.copy(alpha = 0.2f), CircleShape), + contentAlignment = Alignment.Center + ) { + Text( + text = it.abbreviation, + color = Color.White, + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.Bold + ) + } + } + } + } +} + +@Composable +fun EventDetailDialog( + event: Event, + onDismiss: () -> Unit, + onDelete: () -> Unit +) { + val timeFormat = SimpleDateFormat("HH:mm", Locale("es", "ES")) + val dateFormat = SimpleDateFormat("dd 'de' MMMM, yyyy", Locale("es", "ES")) + + Dialog(onDismissRequest = onDismiss) { + Card( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + shape = RoundedCornerShape(16.dp), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surface + ) + ) { + Column( + modifier = Modifier.padding(20.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "Titulo", + style = MaterialTheme.typography.headlineMedium, + fontWeight = FontWeight.Bold + ) + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + IconButton(onClick = onDelete) { + Icon( + Icons.Default.Delete, + contentDescription = "Eliminar", + tint = MaterialTheme.colorScheme.onSurface + ) + } + IconButton(onClick = onDismiss) { + Icon( + Icons.Default.Close, + contentDescription = "Cerrar", + tint = MaterialTheme.colorScheme.onSurface + ) + } + } + } + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = dateFormat.format(Date(event.date)), + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSurface + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "${timeFormat.format(Date(event.startTime))} - ${ + timeFormat.format( + Date( + event.endTime + ) + ) + }", + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSurface + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = "Descripción", + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colorScheme.onSurface + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = event.description.ifEmpty { "Sin descripción" }, + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.8f) + ) + + event.subject?.let { + Spacer(modifier = Modifier.height(16.dp)) + Card( + modifier = Modifier.align(Alignment.End), + colors = CardDefaults.cardColors( + containerColor = Color(it.color) + ), + shape = RoundedCornerShape(50) + ) { + Text( + text = it.abbreviation, + modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), + color = Color.White, + style = MaterialTheme.typography.labelLarge, + fontWeight = FontWeight.Bold + ) + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/list/EventsListState.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/list/EventsListState.kt new file mode 100644 index 0000000..5a75250 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/list/EventsListState.kt @@ -0,0 +1,19 @@ +package com.diegocayo.organizame.presentation.features.main.events.list + +import com.diegocayo.organizame.domain.model.Event + +data class EventsListState( + val events: List = emptyList(), + val selectedDate: Long = System.currentTimeMillis(), + val isLoading: Boolean = false, + val error: String? = null +) + +sealed class EventsListEvent { + data object LoadEvents : EventsListEvent() + data class DeleteEvent(val event: Event) : EventsListEvent() + data object NavigateToCreateEvent : EventsListEvent() + data class ChangeDate(val date: Long) : EventsListEvent() + data object NextDay : EventsListEvent() + data object PreviousDay : EventsListEvent() +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/list/EventsListViewModel.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/list/EventsListViewModel.kt new file mode 100644 index 0000000..7192aa4 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/events/list/EventsListViewModel.kt @@ -0,0 +1,108 @@ +package com.diegocayo.organizame.presentation.features.main.events.list + +import android.icu.util.Calendar +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.diegocayo.organizame.domain.model.Event +import com.diegocayo.organizame.domain.repository.EventRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import javax.inject.Inject + +@HiltViewModel +class EventsListViewModel @Inject constructor( + private val eventRepository: EventRepository +) : ViewModel() { + + private val _state = MutableStateFlow(EventsListState()) + val state: StateFlow = _state.asStateFlow() + private val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale("es", "ES")) + + init { + loadEvents() + } + + fun onEvent(event: EventsListEvent) { + when (event) { + is EventsListEvent.LoadEvents -> loadEvents() + is EventsListEvent.DeleteEvent -> deleteEvent(event.event) + is EventsListEvent.NavigateToCreateEvent -> {} // Manejado por la UI + is EventsListEvent.ChangeDate -> { + _state.value = _state.value.copy(selectedDate = event.date) + loadEvents() + } + + is EventsListEvent.NextDay -> { + val calendar = Calendar.getInstance().apply { + timeInMillis = _state.value.selectedDate + add(Calendar.DAY_OF_MONTH, 1) + } + _state.value = _state.value.copy(selectedDate = calendar.timeInMillis) + loadEvents() + } + + is EventsListEvent.PreviousDay -> { + val calendar = Calendar.getInstance().apply { + timeInMillis = _state.value.selectedDate + add(Calendar.DAY_OF_MONTH, -1) + } + _state.value = _state.value.copy(selectedDate = calendar.timeInMillis) + loadEvents() + } + } + } + + private fun loadEvents() { + viewModelScope.launch { + _state.value = _state.value.copy(isLoading = true) + Log.d( + "EventsListViewModel", + "Cargando eventos para la fecha: ${dateFormat.format(Date(_state.value.selectedDate))}" + ) + + eventRepository.getEventsByDate(_state.value.selectedDate) + .onEach { events -> + Log.d("EventsListViewModel", "Eventos cargados: ${events.size}") + events.forEach { event -> + Log.d( + "EventsListViewModel", + "Evento: ${event.title} - Fecha: ${dateFormat.format(Date(event.date))}" + ) + } + _state.value = _state.value.copy( + events = events, + isLoading = false + ) + } + .catch { e -> + Log.e("EventsListViewModel", "Error al cargar eventos", e) + _state.value = _state.value.copy( + error = e.message, + isLoading = false + ) + } + .launchIn(viewModelScope) + } + } + + private fun deleteEvent(event: Event) { + viewModelScope.launch { + try { + eventRepository.deleteEvent(event) + } catch (e: Exception) { + Log.e("EventsListViewModel", "Error al eliminar evento", e) + _state.value = _state.value.copy(error = e.message) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/profile/ProfileScreen.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/profile/ProfileScreen.kt new file mode 100644 index 0000000..a206a2b --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/profile/ProfileScreen.kt @@ -0,0 +1,140 @@ +package com.diegocayo.organizame.presentation.features.main.profile + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Person +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +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.graphics.vector.rememberVectorPainter +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavHostController +import com.diegocayo.organizame.R +import com.diegocayo.organizame.presentation.navigation.AppScreen + +@Composable +fun ProfileScreen( + navController: NavHostController, + viewModel: ProfileViewModel = hiltViewModel() +) { + var showDeleteConfirmation by remember { mutableStateOf(false) } + + Column( + modifier = Modifier + .fillMaxSize() + .padding(16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Image( + painter = rememberVectorPainter(Icons.Default.Person), + contentDescription = "Profile Picture", + modifier = Modifier + .size(120.dp) + .clip(CircleShape) + ) + + Spacer(modifier = Modifier.height(24.dp)) + + viewModel.user?.let { user -> + Text( + text = "${user.name} ${user.surname}", + style = MaterialTheme.typography.headlineMedium.copy( + fontWeight = FontWeight.Bold + ) + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = stringResource(R.string.text_birthday) + ": ${user.birthdate}", + style = MaterialTheme.typography.bodyLarge + ) + } + + Spacer(modifier = Modifier.height(32.dp)) + + Button( + onClick = { + viewModel.logout { + navController.navigate(AppScreen.Welcome.route) { + popUpTo(AppScreen.Main.route) { + inclusive = true + } + } + } + } + ) { + Text(stringResource(R.string.p_view_edit_profile)) + } + + Spacer(modifier = Modifier.height(16.dp)) + + Button( + onClick = { showDeleteConfirmation = true }, + colors = ButtonDefaults.buttonColors( + containerColor = Color.Red, + contentColor = Color.White + ) + ) { + Text(stringResource(R.string.p_view_delete_account)) + } + } + + if (showDeleteConfirmation) { + AlertDialog( + onDismissRequest = { showDeleteConfirmation = false }, + title = { Text(stringResource(R.string.info_confirm_delete_account)) }, + text = { Text(stringResource(R.string.info_delete_acount)) }, + confirmButton = { + TextButton( + onClick = { + viewModel.deleteAccount { + navController.navigate(AppScreen.Welcome.route) { + popUpTo(AppScreen.Main.route) { + inclusive = true + } + } + } + showDeleteConfirmation = false + }, + colors = ButtonDefaults.textButtonColors( + contentColor = Color.Red + ) + ) { + Text(stringResource(R.string.text_btn_yes_delete)) + } + }, + dismissButton = { + TextButton( + onClick = { showDeleteConfirmation = false } + ) { + Text(stringResource(R.string.text_btn_no_cancel)) + } + } + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/profile/ProfileViewModel.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/profile/ProfileViewModel.kt new file mode 100644 index 0000000..6037be1 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/profile/ProfileViewModel.kt @@ -0,0 +1,89 @@ +package com.diegocayo.organizame.presentation.features.main.profile + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.diegocayo.organizame.data.local.OrganizaMeDatabase +import com.diegocayo.organizame.data.local.preferences.PreferencesDataStore +import com.diegocayo.organizame.domain.model.User +import com.diegocayo.organizame.domain.repository.EventRepository +import com.diegocayo.organizame.domain.repository.SubjectRepository +import com.diegocayo.organizame.domain.repository.TaskRepository +import com.diegocayo.organizame.domain.usecase.GetUserUseCase +import com.diegocayo.organizame.domain.usecase.SetLoginStatusUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class ProfileViewModel @Inject constructor( + private val getUserUseCase: GetUserUseCase, + private val setLoginStatusUseCase: SetLoginStatusUseCase, + private val database: OrganizaMeDatabase, + private val preferencesDataStore: PreferencesDataStore, + private val taskRepository: TaskRepository, + private val subjectRepository: SubjectRepository, + private val eventRepository: EventRepository +) : ViewModel() { + + var user by mutableStateOf(null) + private set + + init { + loadUserData() + } + + private fun loadUserData() { + getUserUseCase.prepare(Unit) + .onEach { userData -> + user = userData + } + .catch { } + .launchIn(viewModelScope) + } + + fun logout(onLogoutComplete: () -> Unit) { + setLoginStatusUseCase.prepare(false) + .onEach { + onLogoutComplete() + } + .catch { } + .launchIn(viewModelScope) + } + + fun deleteAccount(onDeleteComplete: () -> Unit) { + viewModelScope.launch { + try { + taskRepository.getAllTasks().firstOrNull()?.forEach { task -> + taskRepository.deleteTask(task) + } + eventRepository.getAllEvents().firstOrNull()?.forEach { event -> + eventRepository.deleteEvent(event) + } + + subjectRepository.getAllSubjects().firstOrNull()?.forEach { subject -> + subjectRepository.deleteSubject(subject) + } + + database.clearAllTables() + + preferencesDataStore.clearPreferences() + + setLoginStatusUseCase.prepare(false) + .onEach { + onDeleteComplete() + } + .catch { } + .launchIn(viewModelScope) + } catch (e: Exception) { + onDeleteComplete() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/create/CreateSubjectEvent.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/create/CreateSubjectEvent.kt new file mode 100644 index 0000000..15b300e --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/create/CreateSubjectEvent.kt @@ -0,0 +1,8 @@ +package com.diegocayo.organizame.presentation.features.main.subjects.create + +sealed class CreateSubjectEvent { + data class OnNameChange(val name: String) : CreateSubjectEvent() + data class OnAbbreviationChange(val abbreviation: String) : CreateSubjectEvent() + data class OnColorChange(val color: Int) : CreateSubjectEvent() + data object OnSubmit : CreateSubjectEvent() +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/create/CreateSubjectScreen.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/create/CreateSubjectScreen.kt new file mode 100644 index 0000000..5f42a9e --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/create/CreateSubjectScreen.kt @@ -0,0 +1,124 @@ +package com.diegocayo.organizame.presentation.features.main.subjects.create + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.Button +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.diegocayo.organizame.R +import com.diegocayo.organizame.presentation.components.ColorPicker + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun CreateSubjectScreen( + onNavigateBack: () -> Unit, + viewModel: CreateSubjectViewModel = hiltViewModel() +) { + val state by viewModel.state.collectAsStateWithLifecycle() + val snackbarHostState = remember { SnackbarHostState() } + val scrollState = rememberScrollState() + + LaunchedEffect(state.error) { + state.error?.let { error -> + snackbarHostState.showSnackbar(error) + } + } + + LaunchedEffect(state.isSuccess) { + if (state.isSuccess) { + onNavigateBack() + } + } + + Scaffold( + topBar = { + TopAppBar( + title = { Text(stringResource(R.string.subjects)) }, + navigationIcon = { + IconButton(onClick = onNavigateBack) { + Icon( + Icons.Default.ArrowBack, + contentDescription = stringResource(R.string.text_back) + ) + } + } + ) + }, + snackbarHost = { SnackbarHost(snackbarHostState) } + ) { paddingValues -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + .padding(16.dp) + .verticalScroll(scrollState), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + OutlinedTextField( + value = state.name, + onValueChange = { viewModel.onEvent(CreateSubjectEvent.OnNameChange(it)) }, + label = { Text(stringResource(R.string.text_name)) }, + modifier = Modifier.fillMaxWidth(), + isError = state.error?.contains("nombre") == true + ) + + OutlinedTextField( + value = state.abbreviation, + onValueChange = { viewModel.onEvent(CreateSubjectEvent.OnAbbreviationChange(it)) }, + label = { Text(stringResource(R.string.s_c_view_abbreviation)) }, + modifier = Modifier.fillMaxWidth(), + isError = state.error?.contains("abreviación") == true + ) + + ColorPicker( + selectedColor = state.color, + onColorSelected = { viewModel.onEvent(CreateSubjectEvent.OnColorChange(it)) } + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Button( + onClick = { viewModel.onEvent(CreateSubjectEvent.OnSubmit) }, + modifier = Modifier.fillMaxWidth(), + enabled = !state.isLoading && state.isFormValid + ) { + if (state.isLoading) { + CircularProgressIndicator( + modifier = Modifier.padding(end = 8.dp), + color = MaterialTheme.colorScheme.onPrimary + ) + } + Text(stringResource(R.string.text_save)) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/create/CreateSubjectState.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/create/CreateSubjectState.kt new file mode 100644 index 0000000..b82a586 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/create/CreateSubjectState.kt @@ -0,0 +1,11 @@ +package com.diegocayo.organizame.presentation.features.main.subjects.create + +data class CreateSubjectState( + val name: String = "", + val abbreviation: String = "", + val color: Int = 0xFF1976D2.toInt(), + val isLoading: Boolean = false, + val error: String? = null, + val isSuccess: Boolean = false, + val isFormValid: Boolean = false +) \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/create/CreateSubjectViewModel.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/create/CreateSubjectViewModel.kt new file mode 100644 index 0000000..c1418b5 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/create/CreateSubjectViewModel.kt @@ -0,0 +1,80 @@ +package com.diegocayo.organizame.presentation.features.main.subjects.create + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.diegocayo.organizame.domain.model.Subject +import com.diegocayo.organizame.domain.usecase.SaveSubjectUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class CreateSubjectViewModel @Inject constructor( + private val saveSubjectUseCase: SaveSubjectUseCase +) : ViewModel() { + + private val _state = MutableStateFlow(CreateSubjectState()) + val state: StateFlow = _state.asStateFlow() + + fun onEvent(event: CreateSubjectEvent) { + when (event) { + is CreateSubjectEvent.OnNameChange -> { + _state.update { it.copy(name = event.name) } + validateForm() + } + + is CreateSubjectEvent.OnAbbreviationChange -> { + _state.update { it.copy(abbreviation = event.abbreviation) } + validateForm() + } + + is CreateSubjectEvent.OnColorChange -> { + _state.update { it.copy(color = event.color) } + validateForm() + } + + CreateSubjectEvent.OnSubmit -> saveSubject() + } + } + + private fun validateForm() { + val currentState = _state.value + val isValid = currentState.name.isNotBlank() && + currentState.abbreviation.isNotBlank() && + currentState.color != 0 + + _state.update { it.copy(isFormValid = isValid) } + } + + private fun saveSubject() { + viewModelScope.launch { + val currentState = state.value + + if (!currentState.isFormValid) { + _state.update { + it.copy(error = "Por favor, complete todos los campos requeridos") + } + return@launch + } + + _state.update { it.copy(isLoading = true, error = null) } + try { + val subject = Subject( + name = currentState.name, + abbreviation = currentState.abbreviation, + color = currentState.color + ) + saveSubjectUseCase(subject) + _state.update { it.copy(isSuccess = true) } + } catch (e: Exception) { + _state.update { it.copy(error = e.message) } + } finally { + _state.update { it.copy(isLoading = false) } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/list/SubjectsListScreen.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/list/SubjectsListScreen.kt new file mode 100644 index 0000000..66da730 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/list/SubjectsListScreen.kt @@ -0,0 +1,159 @@ +package com.diegocayo.organizame.presentation.features.main.subjects.list + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.Delete +import androidx.compose.material3.Card +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +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.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavController +import com.diegocayo.organizame.domain.model.Subject +import com.diegocayo.organizame.presentation.navigation.AppScreen + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SubjectsListScreen( + navController: NavController, + viewModel: SubjectsListViewModel = hiltViewModel() +) { + val state by viewModel.state.collectAsStateWithLifecycle() + val snackbarHostState = remember { SnackbarHostState() } + + LaunchedEffect(state.error) { + state.error?.let { error -> + snackbarHostState.showSnackbar(error) + } + } + + Scaffold( + topBar = { + TopAppBar( + title = { Text("Asignaturas") } + ) + }, + floatingActionButton = { + FloatingActionButton( + onClick = { navController.navigate(AppScreen.Main.Subjects.Create.route) } + ) { + Icon(Icons.Default.Add, contentDescription = "Añadir asignatura") + } + }, + snackbarHost = { SnackbarHost(snackbarHostState) } + ) { paddingValues -> + Box( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues) + ) { + if (state.isLoading) { + CircularProgressIndicator( + modifier = Modifier.align(Alignment.Center) + ) + } else if (state.subjects.isEmpty()) { + Text( + text = "No hay asignaturas", + modifier = Modifier.align(Alignment.Center) + ) + } else { + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 16.dp, vertical = 8.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + items(state.subjects) { subject -> + SubjectItem( + subject = subject, + onDelete = { viewModel.onEvent(SubjectsListEvent.DeleteSubject(subject)) } + ) + } + } + } + } + } +} + +@Composable +private fun SubjectItem( + subject: Subject, + onDelete: () -> Unit, + modifier: Modifier = Modifier +) { + Card( + modifier = modifier.fillMaxWidth() + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .size(40.dp) + .clip(CircleShape) + .background(Color(subject.color)) + ) + + Column( + modifier = Modifier + .weight(1f) + .padding(start = 16.dp) + ) { + Text( + text = subject.name, + style = MaterialTheme.typography.titleMedium, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + + Text( + text = subject.abbreviation, + style = MaterialTheme.typography.titleMedium, + modifier = Modifier.padding(start = 8.dp, end = 8.dp) + ) + + IconButton(onClick = onDelete) { + Icon( + imageVector = Icons.Default.Delete, + contentDescription = "Eliminar asignatura", + tint = MaterialTheme.colorScheme.error + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/list/SubjectsListState.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/list/SubjectsListState.kt new file mode 100644 index 0000000..fb59a97 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/list/SubjectsListState.kt @@ -0,0 +1,9 @@ +package com.diegocayo.organizame.presentation.features.main.subjects.list + +import com.diegocayo.organizame.domain.model.Subject + +data class SubjectsListState( + val subjects: List = emptyList(), + val isLoading: Boolean = false, + val error: String? = null +) \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/list/SubjectsListViewModel.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/list/SubjectsListViewModel.kt new file mode 100644 index 0000000..9fe20ed --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/subjects/list/SubjectsListViewModel.kt @@ -0,0 +1,77 @@ +package com.diegocayo.organizame.presentation.features.main.subjects.list + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.diegocayo.organizame.domain.model.Subject +import com.diegocayo.organizame.domain.repository.SubjectRepository +import com.diegocayo.organizame.domain.usecase.GetAllSubjectsUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import javax.inject.Inject + +sealed class SubjectsListEvent { + data class DeleteSubject(val subject: Subject) : SubjectsListEvent() +} + +@HiltViewModel +class SubjectsListViewModel @Inject constructor( + private val getAllSubjectsUseCase: GetAllSubjectsUseCase, + private val subjectRepository: SubjectRepository +) : ViewModel() { + + private val _state = MutableStateFlow(SubjectsListState()) + val state: StateFlow = _state.asStateFlow() + + init { + loadSubjects() + } + + fun onEvent(event: SubjectsListEvent) { + when (event) { + is SubjectsListEvent.DeleteSubject -> { + deleteSubject(event.subject) + } + } + } + + private fun loadSubjects() { + _state.update { it.copy(isLoading = true) } + getAllSubjectsUseCase() + .onEach { subjects -> + _state.update { + it.copy( + subjects = subjects, + isLoading = false, + error = null + ) + } + } + .catch { error -> + _state.update { + it.copy( + isLoading = false, + error = error.message + ) + } + } + .launchIn(viewModelScope) + } + + private fun deleteSubject(subject: Subject) { + viewModelScope.launch { + try { + subjectRepository.deleteSubject(subject) + + } catch (e: Exception) { + _state.update { it.copy(error = "Error al eliminar la asignatura: ${e.message}") } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/create/CreateTaskScreen.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/create/CreateTaskScreen.kt new file mode 100644 index 0000000..09a4d1b --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/create/CreateTaskScreen.kt @@ -0,0 +1,281 @@ +package com.diegocayo.organizame.presentation.features.main.tasks.create + +import android.app.DatePickerDialog +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.CalendarToday +import androidx.compose.material3.Button +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExposedDropdownMenuBox +import androidx.compose.material3.ExposedDropdownMenuDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SegmentedButton +import androidx.compose.material3.SingleChoiceSegmentedButtonRow +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import com.diegocayo.organizame.R +import com.diegocayo.organizame.data.local.entity.TaskPriority +import com.diegocayo.organizame.domain.model.Subject +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date +import java.util.Locale + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun CreateTaskScreen( + onNavigateBack: () -> Unit, + viewModel: CreateTaskViewModel = hiltViewModel() +) { + val state by viewModel.state.collectAsState() + val context = LocalContext.current + + LaunchedEffect(state.isTaskCreated) { + if (state.isTaskCreated) { + onNavigateBack() + } + } + + if (state.showDatePicker) { + val calendar = Calendar.getInstance().apply { + timeInMillis = state.scheduledDate + } + + DatePickerDialog( + context, + { _, year, month, dayOfMonth -> + calendar.set(year, month, dayOfMonth) + viewModel.onEvent(CreateTaskEvent.OnDateSelect(calendar.timeInMillis)) + }, + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.get(Calendar.DAY_OF_MONTH) + ).show() + + viewModel.onEvent(CreateTaskEvent.OnHideDatePicker) + } + + Scaffold( + topBar = { + TopAppBar( + title = { Text(stringResource(R.string.t_c_view_new_task)) }, + navigationIcon = { + IconButton(onClick = onNavigateBack) { + Icon( + Icons.Default.ArrowBack, + contentDescription = stringResource(R.string.text_back) + ) + } + } + ) + } + ) { padding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(padding) + .padding(16.dp) + .verticalScroll(rememberScrollState()) + ) { + OutlinedTextField( + value = state.title, + onValueChange = { viewModel.onEvent(CreateTaskEvent.OnTitleChange(it)) }, + label = { Text(stringResource(R.string.text_title)) }, + modifier = Modifier.fillMaxWidth(), + isError = state.error?.contains("título") == true, + supportingText = { + if (state.error?.contains("título") == true) { + Text(stringResource(R.string.info_title_compulsory)) + } + } + ) + + Spacer(modifier = Modifier.height(16.dp)) + + OutlinedTextField( + value = state.description, + onValueChange = { viewModel.onEvent(CreateTaskEvent.OnDescriptionChange(it)) }, + label = { Text(stringResource(R.string.text_description)) }, + modifier = Modifier.fillMaxWidth(), + minLines = 3, + isError = state.error?.contains("descripción") == true, + supportingText = { + if (state.error?.contains("descripción") == true) { + Text("La descripción es obligatoria") + } + } + ) + + Spacer(modifier = Modifier.height(16.dp)) + + OutlinedTextField( + value = formatDate(state.scheduledDate), + onValueChange = { }, + readOnly = true, + label = { Text(stringResource(R.string.t_c_view_scheduled_date)) }, + trailingIcon = { + Icon( + Icons.Default.CalendarToday, + contentDescription = stringResource(R.string.t_c_view_scheduled_date), + modifier = Modifier.clickable { + viewModel.onEvent(CreateTaskEvent.OnShowDatePicker) + } + ) + }, + modifier = Modifier.fillMaxWidth() + ) + + Spacer(modifier = Modifier.height(16.dp)) + + SubjectDropdown( + selectedSubject = state.selectedSubject, + subjects = state.subjects, + onSubjectSelected = { viewModel.onEvent(CreateTaskEvent.OnSubjectSelect(it)) } + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = stringResource(R.string.t_c_view_priority), + style = MaterialTheme.typography.titleMedium + ) + + Spacer(modifier = Modifier.height(8.dp)) + + PrioritySelector( + selectedPriority = state.priority, + onPrioritySelected = { viewModel.onEvent(CreateTaskEvent.OnPrioritySelect(it)) } + ) + + Spacer(modifier = Modifier.height(24.dp)) + + Button( + onClick = { viewModel.onEvent(CreateTaskEvent.OnCreateTask) }, + modifier = Modifier.fillMaxWidth(), + enabled = !state.isLoading && state.isFormValid + ) { + if (state.isLoading) { + CircularProgressIndicator( + modifier = Modifier.padding(end = 8.dp) + ) + } + Text(stringResource(R.string.t_c_view_create_task)) + } + + state.error?.let { error -> + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = error, + color = MaterialTheme.colorScheme.error, + style = MaterialTheme.typography.bodyMedium + ) + } + } + } +} + +private fun formatDate(timestamp: Long): String { + val sdf = SimpleDateFormat("dd/MM/yyyy", Locale("es", "ES")) + return sdf.format(Date(timestamp)) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SubjectDropdown( + selectedSubject: Subject?, + subjects: List, + onSubjectSelected: (Subject?) -> Unit +) { + var expanded by remember { mutableStateOf(false) } + + ExposedDropdownMenuBox( + expanded = expanded, + onExpandedChange = { expanded = it } + ) { + OutlinedTextField( + value = selectedSubject?.name ?: stringResource(R.string.text_no_subject), + onValueChange = {}, + readOnly = true, + trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, + modifier = Modifier + .fillMaxWidth() + .menuAnchor(), + label = { Text(stringResource(R.string.subjects)) } + ) + + ExposedDropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false } + ) { + DropdownMenuItem( + text = { Text("Sin asignatura") }, + onClick = { + onSubjectSelected(null) + expanded = false + } + ) + subjects.forEach { subject -> + DropdownMenuItem( + text = { Text(subject.name) }, + onClick = { + onSubjectSelected(subject) + expanded = false + } + ) + } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun PrioritySelector( + selectedPriority: TaskPriority, + onPrioritySelected: (TaskPriority) -> Unit +) { + SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) { + TaskPriority.values().forEach { priority -> + SegmentedButton( + selected = selectedPriority == priority, + onClick = { onPrioritySelected(priority) }, + shape = MaterialTheme.shapes.small, + modifier = Modifier.weight(1f) + ) { + Text( + text = when (priority) { + TaskPriority.HIGH -> stringResource(R.string.t_c_pri_high) + TaskPriority.MEDIUM -> stringResource(R.string.t_c_pri_medium) + TaskPriority.LOW -> stringResource(R.string.t_c_pri_low) + } + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/create/CreateTaskState.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/create/CreateTaskState.kt new file mode 100644 index 0000000..127bd59 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/create/CreateTaskState.kt @@ -0,0 +1,29 @@ +package com.diegocayo.organizame.presentation.features.main.tasks.create + +import com.diegocayo.organizame.data.local.entity.TaskPriority +import com.diegocayo.organizame.domain.model.Subject + +data class CreateTaskState( + val title: String = "", + val description: String = "", + val selectedSubject: Subject? = null, + val subjects: List = emptyList(), + val priority: TaskPriority = TaskPriority.LOW, + val scheduledDate: Long = System.currentTimeMillis(), + val showDatePicker: Boolean = false, + val isLoading: Boolean = false, + val isTaskCreated: Boolean = false, + val error: String? = null, + val isFormValid: Boolean = false +) + +sealed class CreateTaskEvent { + data class OnTitleChange(val title: String) : CreateTaskEvent() + data class OnDescriptionChange(val description: String) : CreateTaskEvent() + data class OnSubjectSelect(val subject: Subject?) : CreateTaskEvent() + data class OnPrioritySelect(val priority: TaskPriority) : CreateTaskEvent() + data class OnDateSelect(val timestamp: Long) : CreateTaskEvent() + data object OnShowDatePicker : CreateTaskEvent() + data object OnHideDatePicker : CreateTaskEvent() + data object OnCreateTask : CreateTaskEvent() +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/create/CreateTaskViewModel.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/create/CreateTaskViewModel.kt new file mode 100644 index 0000000..f085718 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/create/CreateTaskViewModel.kt @@ -0,0 +1,136 @@ +package com.diegocayo.organizame.presentation.features.main.tasks.create + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.diegocayo.organizame.data.local.entity.TaskStatus +import com.diegocayo.organizame.domain.model.Task +import com.diegocayo.organizame.domain.repository.SubjectRepository +import com.diegocayo.organizame.domain.repository.TaskRepository +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 + +@HiltViewModel +class CreateTaskViewModel @Inject constructor( + private val taskRepository: TaskRepository, + private val subjectRepository: SubjectRepository +) : ViewModel() { + + private val _state = MutableStateFlow(CreateTaskState()) + val state: StateFlow = _state.asStateFlow() + + init { + loadSubjects() + } + + private fun loadSubjects() { + viewModelScope.launch { + try { + subjectRepository.getAllSubjects().collect { subjects -> + _state.value = _state.value.copy(subjects = subjects) + } + } catch (e: Exception) { + _state.value = _state.value.copy(error = e.message) + } + } + } + + fun onEvent(event: CreateTaskEvent) { + when (event) { + is CreateTaskEvent.OnTitleChange -> { + _state.value = _state.value.copy( + title = event.title, + error = null + ) + validateForm() + } + + is CreateTaskEvent.OnDescriptionChange -> { + _state.value = _state.value.copy( + description = event.description, + error = null + ) + validateForm() + } + + is CreateTaskEvent.OnSubjectSelect -> { + _state.value = _state.value.copy( + selectedSubject = event.subject, + error = null + ) + validateForm() + } + + is CreateTaskEvent.OnPrioritySelect -> { + _state.value = _state.value.copy(priority = event.priority) + } + + is CreateTaskEvent.OnDateSelect -> { + _state.value = _state.value.copy( + scheduledDate = event.timestamp, + showDatePicker = false + ) + } + + is CreateTaskEvent.OnShowDatePicker -> { + _state.value = _state.value.copy(showDatePicker = true) + } + + is CreateTaskEvent.OnHideDatePicker -> { + _state.value = _state.value.copy(showDatePicker = false) + } + + is CreateTaskEvent.OnCreateTask -> createTask() + } + } + + private fun validateForm() { + val currentState = _state.value + val isValid = currentState.title.isNotBlank() && + currentState.description.isNotBlank() + + _state.value = currentState.copy(isFormValid = isValid) + } + + private fun createTask() { + val currentState = _state.value + + if (currentState.title.isBlank()) { + _state.value = currentState.copy(error = "El título es obligatorio") + return + } + + if (currentState.description.isBlank()) { + _state.value = currentState.copy(error = "La descripción es obligatoria") + return + } + + viewModelScope.launch { + _state.value = currentState.copy(isLoading = true) + try { + val task = Task( + title = currentState.title, + description = currentState.description, + subject = currentState.selectedSubject, + priority = currentState.priority, + status = TaskStatus.PENDING, + scheduledDate = currentState.scheduledDate, + createdAt = System.currentTimeMillis() + ) + taskRepository.insertTask(task) + _state.value = currentState.copy( + isLoading = false, + isTaskCreated = true + ) + } catch (e: Exception) { + _state.value = currentState.copy( + isLoading = false, + error = e.message + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/list/TasksListScreen.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/list/TasksListScreen.kt new file mode 100644 index 0000000..1be3a85 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/list/TasksListScreen.kt @@ -0,0 +1,381 @@ +package com.diegocayo.organizame.presentation.features.main.tasks.list + +import android.app.DatePickerDialog +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Add +import androidx.compose.material.icons.filled.ChevronLeft +import androidx.compose.material.icons.filled.ChevronRight +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Checkbox +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.drawscope.Stroke +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavController +import com.diegocayo.organizame.R +import com.diegocayo.organizame.data.local.entity.TaskStatus +import com.diegocayo.organizame.domain.model.Task +import com.diegocayo.organizame.presentation.navigation.AppScreen +import java.text.SimpleDateFormat +import java.util.Calendar +import java.util.Date +import java.util.Locale + +@Composable +fun TasksListScreen( + navController: NavController, + viewModel: TasksListViewModel = hiltViewModel() +) { + val state by viewModel.state.collectAsState() + + Scaffold( + floatingActionButton = { + FloatingActionButton( + onClick = { navController.navigate(AppScreen.Main.Tasks.Create.route) } + ) { + Icon(Icons.Default.Add, contentDescription = "Crear tarea") + } + } + ) { padding -> + Box( + modifier = Modifier + .fillMaxSize() + .padding(padding) + ) { + if (state.isLoading) { + CircularProgressIndicator(modifier = Modifier.align(Alignment.Center)) + } else { + TaskList( + pendingTasks = state.pendingTasks, + completedTasks = state.completedTasks, + selectedDate = state.selectedDate, + onTaskStatusChange = { task, completed -> + viewModel.onEvent(TasksListEvent.UpdateTaskStatus(task.id, completed)) + }, + onPreviousDay = { viewModel.onEvent(TasksListEvent.PreviousDay) }, + onNextDay = { viewModel.onEvent(TasksListEvent.NextDay) }, + onDateSelected = { date -> viewModel.onEvent(TasksListEvent.ChangeDate(date)) } + ) + } + } + } +} + +@Composable +fun TaskList( + pendingTasks: List, + completedTasks: List, + selectedDate: Long, + onTaskStatusChange: (Task, Boolean) -> Unit, + onPreviousDay: () -> Unit, + onNextDay: () -> Unit, + onDateSelected: (Long) -> Unit +) { + LazyColumn( + modifier = Modifier + .fillMaxSize() + .padding(16.dp) + ) { + item { + TaskProgressCard( + pendingCount = pendingTasks.size, + completedCount = completedTasks.size, + selectedDate = selectedDate, + onPreviousDay = onPreviousDay, + onNextDay = onNextDay, + onDateSelected = onDateSelected + ) + Spacer(modifier = Modifier.height(16.dp)) + } + + items(pendingTasks) { task -> + TaskItem( + task = task, + onStatusChange = { completed -> onTaskStatusChange(task, completed) } + ) + Spacer(modifier = Modifier.height(8.dp)) + } + + if (completedTasks.isNotEmpty()) { + item { + Text( + text = stringResource(R.string.text_complete_btn), + style = MaterialTheme.typography.titleMedium, + modifier = Modifier.padding(vertical = 8.dp) + ) + } + + items(completedTasks) { task -> + TaskItem( + task = task, + onStatusChange = { completed -> onTaskStatusChange(task, completed) } + ) + Spacer(modifier = Modifier.height(8.dp)) + } + } + } +} + +@Composable +fun TaskProgressCard( + pendingCount: Int, + completedCount: Int, + selectedDate: Long, + onPreviousDay: () -> Unit, + onNextDay: () -> Unit, + onDateSelected: (Long) -> Unit +) { + val total = pendingCount + completedCount + val progress = if (total > 0) completedCount.toFloat() / total else 0f + val dateFormat = SimpleDateFormat("dd 'de' MMMM, yyyy", Locale("es", "ES")) + val context = LocalContext.current + val calendar = Calendar.getInstance() + + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surface + ) + ) { + Column( + modifier = Modifier.padding(16.dp), + horizontalAlignment = Alignment.Start + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + IconButton(onClick = onPreviousDay) { + Icon(Icons.Default.ChevronLeft, contentDescription = "Día anterior") + } + + Text( + text = dateFormat.format(Date(selectedDate)), + style = MaterialTheme.typography.titleLarge, + modifier = Modifier.clickable { + calendar.timeInMillis = selectedDate + DatePickerDialog( + context, + { _, year, month, dayOfMonth -> + calendar.set(year, month, dayOfMonth) + onDateSelected(calendar.timeInMillis) + }, + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.get(Calendar.DAY_OF_MONTH) + ).show() + } + ) + + IconButton(onClick = onNextDay) { + Icon(Icons.Default.ChevronRight, contentDescription = "Día siguiente") + } + } + + Box( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp), + contentAlignment = Alignment.Center + ) { + CircularProgressIndicator( + progress = progress, + size = 120.dp, + strokeWidth = 8.dp + ) + + Text( + text = "${(progress * 100).toInt()}%", + style = MaterialTheme.typography.titleLarge.copy( + fontWeight = FontWeight.Bold + ) + ) + } + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Box( + modifier = Modifier + .size(8.dp) + .background( + color = MaterialTheme.colorScheme.primary, + shape = CircleShape + ) + ) + Text( + text = "DONE $completedCount", + style = MaterialTheme.typography.bodyMedium + ) + } + + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + Box( + modifier = Modifier + .size(8.dp) + .background( + color = MaterialTheme.colorScheme.error, + shape = CircleShape + ) + ) + Text( + text = "PENDING $pendingCount", + style = MaterialTheme.typography.bodyMedium + ) + } + } + } + } +} + +@Composable +fun CircularProgressIndicator( + progress: Float, + size: Dp, + strokeWidth: Dp, + backgroundColor: Color = MaterialTheme.colorScheme.surfaceVariant, + progressColor: Color = Color(0xFFFFEB3B) +) { + Box( + modifier = Modifier + .size(size) + .aspectRatio(1f), + contentAlignment = Alignment.Center + ) { + Canvas(modifier = Modifier.size(size)) { + drawArc( + color = backgroundColor, + startAngle = 0f, + sweepAngle = 360f, + useCenter = false, + style = Stroke( + width = strokeWidth.toPx(), + cap = StrokeCap.Round + ) + ) + + drawArc( + color = progressColor, + startAngle = -90f, + sweepAngle = progress * 360f, + useCenter = false, + style = Stroke( + width = strokeWidth.toPx(), + cap = StrokeCap.Round + ) + ) + } + } +} + +@Composable +fun TaskItem( + task: Task, + onStatusChange: (Boolean) -> Unit +) { + val isCompleted = task.status == TaskStatus.COMPLETED + + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = if (isCompleted) + MaterialTheme.colorScheme.surfaceVariant + else + MaterialTheme.colorScheme.surface + ) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Checkbox( + checked = isCompleted, + onCheckedChange = onStatusChange + ) + + Column( + modifier = Modifier + .weight(1f) + .padding(start = 8.dp, end = 8.dp) + ) { + Text( + text = task.title, + style = MaterialTheme.typography.titleMedium, + textDecoration = if (isCompleted) TextDecoration.LineThrough else TextDecoration.None, + color = if (isCompleted) MaterialTheme.colorScheme.outline else MaterialTheme.colorScheme.onSurface + ) + if (task.description.isNotEmpty()) { + Text( + text = task.description, + style = MaterialTheme.typography.bodyMedium, + color = if (isCompleted) MaterialTheme.colorScheme.outline else MaterialTheme.colorScheme.onSurfaceVariant + ) + } + } + + task.subject?.let { + Card( + colors = CardDefaults.cardColors( + containerColor = Color(it.color).copy(alpha = if (isCompleted) 0.6f else 1f) + ), + modifier = Modifier.height(24.dp) + ) { + Text( + text = it.abbreviation, + color = Color.White, + style = MaterialTheme.typography.labelMedium, + modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp) + ) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/list/TasksListState.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/list/TasksListState.kt new file mode 100644 index 0000000..92ea352 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/list/TasksListState.kt @@ -0,0 +1,22 @@ +package com.diegocayo.organizame.presentation.features.main.tasks.list + +import com.diegocayo.organizame.domain.model.Task + +data class TasksListState( + val tasks: List = emptyList(), + val pendingTasks: List = emptyList(), + val completedTasks: List = emptyList(), + val selectedDate: Long = System.currentTimeMillis(), + val isLoading: Boolean = false, + val error: String? = null +) + +sealed class TasksListEvent { + data object LoadTasks : TasksListEvent() + data class UpdateTaskStatus(val taskId: Long, val completed: Boolean) : TasksListEvent() + data class DeleteTask(val task: Task) : TasksListEvent() + data object NavigateToCreateTask : TasksListEvent() + data class ChangeDate(val date: Long) : TasksListEvent() + data object NextDay : TasksListEvent() + data object PreviousDay : TasksListEvent() +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/list/TasksListViewModel.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/list/TasksListViewModel.kt new file mode 100644 index 0000000..ee5c9b7 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/main/tasks/list/TasksListViewModel.kt @@ -0,0 +1,123 @@ +package com.diegocayo.organizame.presentation.features.main.tasks.list + +import android.icu.util.Calendar +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.diegocayo.organizame.data.local.entity.TaskStatus +import com.diegocayo.organizame.domain.model.Task +import com.diegocayo.organizame.domain.repository.TaskRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class TasksListViewModel @Inject constructor( + private val taskRepository: TaskRepository +) : ViewModel() { + + private val _state = MutableStateFlow(TasksListState()) + val state: StateFlow = _state.asStateFlow() + + init { + loadTasks() + } + + fun onEvent(event: TasksListEvent) { + when (event) { + is TasksListEvent.LoadTasks -> loadTasks() + is TasksListEvent.UpdateTaskStatus -> updateTaskStatus(event.taskId, event.completed) + is TasksListEvent.DeleteTask -> deleteTask(event.task) + is TasksListEvent.NavigateToCreateTask -> {} // Manejado por la UI + is TasksListEvent.ChangeDate -> { + _state.value = _state.value.copy(selectedDate = event.date) + loadTasks() + } + + is TasksListEvent.NextDay -> { + val calendar = Calendar.getInstance().apply { + timeInMillis = _state.value.selectedDate + add(Calendar.DAY_OF_MONTH, 1) + } + _state.value = _state.value.copy(selectedDate = calendar.timeInMillis) + loadTasks() + } + + is TasksListEvent.PreviousDay -> { + val calendar = Calendar.getInstance().apply { + timeInMillis = _state.value.selectedDate + add(Calendar.DAY_OF_MONTH, -1) + } + _state.value = _state.value.copy(selectedDate = calendar.timeInMillis) + loadTasks() + } + } + } + + private fun loadTasks() { + viewModelScope.launch { + _state.value = _state.value.copy(isLoading = true) + + taskRepository.getAllTasks() + .onEach { tasks -> + val filteredTasks = filterTasksByDate(tasks, _state.value.selectedDate) + _state.value = _state.value.copy( + tasks = filteredTasks, + pendingTasks = filteredTasks.filter { it.status == TaskStatus.PENDING }, + completedTasks = filteredTasks.filter { it.status == TaskStatus.COMPLETED }, + isLoading = false + ) + } + .catch { e -> + _state.value = _state.value.copy( + error = e.message, + isLoading = false + ) + } + .launchIn(viewModelScope) + } + } + + private fun filterTasksByDate(tasks: List, date: Long): List { + val calendar = Calendar.getInstance() + calendar.timeInMillis = date + calendar.set(Calendar.HOUR_OF_DAY, 0) + calendar.set(Calendar.MINUTE, 0) + calendar.set(Calendar.SECOND, 0) + calendar.set(Calendar.MILLISECOND, 0) + val startOfDay = calendar.timeInMillis + + calendar.add(Calendar.DAY_OF_MONTH, 1) + val startOfNextDay = calendar.timeInMillis + + return tasks.filter { task -> + task.scheduledDate in startOfDay until startOfNextDay + } + } + + private fun updateTaskStatus(taskId: Long, completed: Boolean) { + viewModelScope.launch { + try { + val newStatus = if (completed) TaskStatus.COMPLETED else TaskStatus.PENDING + taskRepository.updateTaskStatus(taskId, newStatus) + } catch (e: Exception) { + _state.value = _state.value.copy(error = e.message) + } + } + } + + private fun deleteTask(task: Task) { + viewModelScope.launch { + try { + taskRepository.deleteTask(task) + } catch (e: Exception) { + _state.value = _state.value.copy(error = e.message) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/welcome/firstStep/FirstStepScreen.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/welcome/firstStep/FirstStepScreen.kt new file mode 100644 index 0000000..fa40c41 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/welcome/firstStep/FirstStepScreen.kt @@ -0,0 +1,260 @@ +package com.diegocayo.organizame.presentation.features.welcome.firstStep + +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.ExperimentalAnimationApi +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.with +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.Button +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.navigation.NavHostController +import com.diegocayo.organizame.R +import com.diegocayo.organizame.presentation.navigation.AppScreen + +@OptIn(ExperimentalAnimationApi::class) +@Composable +fun FirstStepScreen( + navController: NavHostController, + viewModel: FirstStepViewModel = hiltViewModel() +) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(32.dp), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + AnimatedContent( + targetState = viewModel.step, + transitionSpec = { fadeIn() with fadeOut() }, + label = "Step Animation" + ) { step -> + when (step) { + 0 -> NameStep( + name = viewModel.name, + error = viewModel.nameError, + onNameChange = { viewModel.validateName(it) } + ) + + 1 -> SurnameStep( + surname = viewModel.surname, + error = viewModel.surnameError, + onSurnameChange = { viewModel.validateSurname(it) } + ) + + 2 -> BirthdateStep( + day = viewModel.birthdateDay, + month = viewModel.birthdateMonth, + year = viewModel.birthdateYear, + error = viewModel.birthdateError, + maxDay = viewModel.maxDay, + maxMonth = viewModel.maxMonth, + maxYear = viewModel.maxYear, + onDayChange = { + viewModel.birthdateDay = it.take(2) + viewModel.validateBirthdate() + }, + onMonthChange = { + viewModel.birthdateMonth = it.take(2) + viewModel.validateBirthdate() + }, + onYearChange = { + viewModel.birthdateYear = it.take(4) + viewModel.validateBirthdate() + } + ) + } + } + + Spacer(modifier = Modifier.height(32.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.End + ) { + if (viewModel.step > 0) { + OutlinedButton( + onClick = { viewModel.previousStep() }, + modifier = Modifier + .weight(1f) + .padding(end = 8.dp) + ) { + Text(stringResource(R.string.text_back)) + } + } + Button( + onClick = { + if (viewModel.step == 2) { + viewModel.saveUserAndLogin { + navController.navigate(AppScreen.Main.route) { + popUpTo(AppScreen.Welcome.route) { + inclusive = true + } + } + } + } else { + viewModel.nextStep() + } + }, + modifier = Modifier.weight(1f), + enabled = viewModel.canProceedToNextStep() + ) { + Text( + if (viewModel.step == 2) stringResource(R.string.text_complete_btn) else stringResource( + R.string.text_next + ) + ) + } + } + } +} + +@Composable +private fun NameStep( + name: String, + error: String?, + onNameChange: (String) -> Unit +) { + Column { + Text(stringResource(R.string.g1_your_name), style = MaterialTheme.typography.headlineSmall) + Spacer(modifier = Modifier.height(16.dp)) + OutlinedTextField( + value = name, + onValueChange = onNameChange, + label = { Text(stringResource(R.string.text_name)) }, + modifier = Modifier.fillMaxWidth(), + isError = error != null, + supportingText = { error?.let { Text(it) } } + ) + } +} + +@Composable +private fun SurnameStep( + surname: String, + error: String?, + onSurnameChange: (String) -> Unit +) { + Column { + Text( + stringResource(R.string.g2_your_surname), + style = MaterialTheme.typography.headlineSmall + ) + Spacer(modifier = Modifier.height(16.dp)) + OutlinedTextField( + value = surname, + onValueChange = onSurnameChange, + label = { Text(stringResource(R.string.text_surname)) }, + modifier = Modifier.fillMaxWidth(), + isError = error != null, + supportingText = { error?.let { Text(it) } } + ) + } +} + +@Composable +private fun BirthdateStep( + day: String, + month: String, + year: String, + error: Int?, + maxDay: Int, + maxMonth: Int, + maxYear: Int, + onDayChange: (String) -> Unit, + onMonthChange: (String) -> Unit, + onYearChange: (String) -> Unit +) { + Column { + Text( + stringResource(R.string.g2_your_birthday), + style = MaterialTheme.typography.headlineSmall + ) + Spacer(modifier = Modifier.height(16.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + OutlinedTextField( + value = day, + onValueChange = { value -> + if (value.isEmpty() || value.all { it.isDigit() }) { + onDayChange(value) + } + }, + label = { Text(stringResource(R.string.text_day)) }, + modifier = Modifier.weight(1f), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + singleLine = true, + isError = error != null + ) + + Spacer(modifier = Modifier.width(8.dp)) + + OutlinedTextField( + value = month, + onValueChange = { value -> + if (value.isEmpty() || value.all { it.isDigit() }) { + onMonthChange(value) + } + }, + label = { Text(stringResource(R.string.text_month)) }, + modifier = Modifier.weight(1f), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + singleLine = true, + isError = error != null + ) + + Spacer(modifier = Modifier.width(8.dp)) + + OutlinedTextField( + value = year, + onValueChange = { value -> + if (value.isEmpty() || value.all { it.isDigit() }) { + onYearChange(value) + } + }, + label = { Text(stringResource(R.string.text_year)) }, + modifier = Modifier.weight(1f), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), + singleLine = true, + isError = error != null + ) + } + + if (error != null) { + Spacer(modifier = Modifier.height(8.dp)) + Text( + text = stringResource(error), + color = MaterialTheme.colorScheme.error, + style = MaterialTheme.typography.bodySmall + ) + } + } +} + +@Composable +fun navigateToNextScreen() { + +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/welcome/firstStep/FirstStepViewModel.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/welcome/firstStep/FirstStepViewModel.kt new file mode 100644 index 0000000..be55f40 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/welcome/firstStep/FirstStepViewModel.kt @@ -0,0 +1,157 @@ +package com.diegocayo.organizame.presentation.features.welcome.firstStep + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.diegocayo.organizame.R +import com.diegocayo.organizame.domain.model.User +import com.diegocayo.organizame.domain.usecase.SaveUserUseCase +import com.diegocayo.organizame.domain.usecase.SetLoginStatusUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import java.util.Calendar +import javax.inject.Inject + +@HiltViewModel +class FirstStepViewModel @Inject constructor( + private val saveUserUseCase: SaveUserUseCase, + private val setLoginStatusUseCase: SetLoginStatusUseCase +) : ViewModel() { + + var step by mutableIntStateOf(0) + private set + + var name by mutableStateOf("") + var surname by mutableStateOf("") + var birthdateDay by mutableStateOf("") + var birthdateMonth by mutableStateOf("") + var birthdateYear by mutableStateOf("") + + var nameError by mutableStateOf(null) + private set + var surnameError by mutableStateOf(null) + private set + var birthdateError by mutableStateOf(null) + private set + + private val currentDate = Calendar.getInstance() + val maxYear = currentDate.get(Calendar.YEAR) + val maxMonth = currentDate.get(Calendar.MONTH) + 1 + val maxDay = currentDate.get(Calendar.DAY_OF_MONTH) + + fun validateName(name: String) { + this.name = name + nameError = when { + name.isBlank() -> "El nombre es obligatorio" + else -> null + } + } + + fun validateSurname(surname: String) { + this.surname = surname + surnameError = when { + surname.isBlank() -> "El apellido es obligatorio" + else -> null + } + } + + fun validateBirthdate() { + try { + val day = birthdateDay.toIntOrNull() ?: 0 + val month = birthdateMonth.toIntOrNull() ?: 0 + val year = birthdateYear.toIntOrNull() ?: 0 + + birthdateError = when { + birthdateDay.isBlank() || birthdateMonth.isBlank() || birthdateYear.isBlank() -> + R.string.info_all_fields_mandatory + + year > maxYear -> R.string.info_year_can_not_later_current_year + year == maxYear && month > maxMonth -> R.string.info_date_later + year == maxYear && month == maxMonth && day > maxDay -> R.string.info_date_later + !isValidDate(day, month, year) -> R.string.info_invalid_date + else -> null + } + + + } catch (e: Exception) { + + } + } + + private fun isValidDate(day: Int, month: Int, year: Int): Boolean { + return try { + val calendar = Calendar.getInstance() + calendar.isLenient = false + calendar.set(Calendar.YEAR, year) + calendar.set(Calendar.MONTH, month - 1) + calendar.set(Calendar.DAY_OF_MONTH, day) + calendar.time + true + } catch (e: Exception) { + false + } + } + + fun canProceedToNextStep(): Boolean { + return when (step) { + 0 -> name.isNotBlank() && nameError == null + 1 -> surname.isNotBlank() && surnameError == null + 2 -> birthdateDay.isNotBlank() && birthdateMonth.isNotBlank() && + birthdateYear.isNotBlank() && birthdateError == null + + else -> false + } + } + + fun nextStep() { + if (step < 2 && canProceedToNextStep()) { + step++ + } + } + + fun previousStep() { + if (step > 0) { + step-- + } + } + + fun saveUserAndLogin(onSuccess: () -> Unit) { + if (!canProceedToNextStep()) return + + val birthdate = "$birthdateDay/$birthdateMonth/$birthdateYear" + val user = User( + name = name, + surname = surname, + birthdate = birthdate + ) + + saveUser(user, onSuccess) + } + + private fun saveUser(user: User, onSuccess: () -> Unit) { + saveUserUseCase.prepare(user) + .onEach { + setLoginStatus(true) { + onSuccess() + } + } + .catch { exception -> + } + .launchIn(viewModelScope) + } + + private fun setLoginStatus(isLoggedIn: Boolean, onSuccess: () -> Unit) { + setLoginStatusUseCase.prepare(isLoggedIn) + .onEach { + onSuccess() + } + .catch { exception -> + } + .launchIn(viewModelScope) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/features/welcome/grettings/GrettingScreen.kt b/app/src/main/java/com/diegocayo/organizame/presentation/features/welcome/grettings/GrettingScreen.kt new file mode 100644 index 0000000..51aadb5 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/features/welcome/grettings/GrettingScreen.kt @@ -0,0 +1,54 @@ +package com.diegocayo.organizame.presentation.features.welcome.grettings + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +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.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController +import com.diegocayo.organizame.presentation.navigation.AppScreen + +@Composable +fun GrettingScreen( + name: String, + navController: NavHostController +) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(32.dp), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = "¡Gracias por elegirnos $name!", + style = MaterialTheme.typography.headlineMedium, + textAlign = TextAlign.Center + ) + + Spacer(modifier = Modifier.height(32.dp)) + + Button( + onClick = { + navController.navigate(AppScreen.Main.route) { + popUpTo(AppScreen.Welcome.route) { + inclusive = true + } + } + }, + modifier = Modifier.fillMaxWidth() + ) { + Text("¡Empecemos!") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/navigation/AppRouter.kt b/app/src/main/java/com/diegocayo/organizame/presentation/navigation/AppRouter.kt new file mode 100644 index 0000000..cf316ac --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/navigation/AppRouter.kt @@ -0,0 +1,87 @@ +package com.diegocayo.organizame.presentation.navigation + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.CheckCircle +import androidx.compose.material.icons.filled.Event +import androidx.compose.material.icons.filled.Person +import androidx.compose.material.icons.filled.School +import androidx.compose.material.icons.outlined.CheckCircle +import androidx.compose.material.icons.outlined.Event +import androidx.compose.material.icons.outlined.Person +import androidx.compose.material.icons.outlined.School +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.navigation.NamedNavArgument +import androidx.navigation.NavType +import androidx.navigation.navArgument +import com.diegocayo.organizame.R + +private object Routes { + const val FIRST_STEP_NAV = "FIRST_STEP_NAV_GRAPH" + const val FIRST_STEP = "first_step" + const val GRETTING = "gretting/{name}" + + const val MAIN_NAV = "MAIN_NAV_GRAPH" + const val TASKS = "tasks" + const val CREATE_TASK = "tasks/create" + const val EVENTS = "events" + const val CREATE_EVENT = "events/create" + const val SUBJECTS = "subjects" + const val CREATE_SUBJECT = "subjects/create" + const val PROFILE = "profile" +} + +sealed class AppScreen(val route: String) { + data object Welcome : AppScreen(Routes.FIRST_STEP_NAV) { + data object FirstSteps : AppScreen(Routes.FIRST_STEP) + data object Gretting : AppScreen(Routes.GRETTING) { + fun createRoute(name: String) = "gretting/$name" + val arguments = listOf( + navArgument("name") { type = NavType.StringType } + ) + } + } + + data object Main : TopLevelDestination(Routes.MAIN_NAV) { + data object Tasks : TopLevelDestination( + route = Routes.TASKS, + title = R.string.tasks, + selectedIcon = Icons.Filled.CheckCircle, + unselectedIcon = Icons.Outlined.CheckCircle + ) { + data object Create : TopLevelDestination(Routes.CREATE_TASK) + } + + data object Events : TopLevelDestination( + route = Routes.EVENTS, + title = R.string.events, + selectedIcon = Icons.Filled.Event, + unselectedIcon = Icons.Outlined.Event + ) { + data object Create : TopLevelDestination(Routes.CREATE_EVENT) + } + + data object Subjects : TopLevelDestination( + route = Routes.SUBJECTS, + title = R.string.subjects, + selectedIcon = Icons.Filled.School, + unselectedIcon = Icons.Outlined.School + ) { + data object Create : TopLevelDestination(Routes.CREATE_SUBJECT) + } + + data object Profile : TopLevelDestination( + route = Routes.PROFILE, + title = R.string.profile, + selectedIcon = Icons.Filled.Person, + unselectedIcon = Icons.Outlined.Person + ) + } +} + +sealed class TopLevelDestination( + val route: String, + val title: Int? = null, + val selectedIcon: ImageVector? = null, + val unselectedIcon: ImageVector? = null, + val navArguments: List = emptyList() +) \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/navigation/BottomNavigationBar.kt b/app/src/main/java/com/diegocayo/organizame/presentation/navigation/BottomNavigationBar.kt new file mode 100644 index 0000000..0084714 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/navigation/BottomNavigationBar.kt @@ -0,0 +1,56 @@ +package com.diegocayo.organizame.presentation.navigation + +import androidx.compose.material3.Icon +import androidx.compose.material3.NavigationBar +import androidx.compose.material3.NavigationBarItem +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.res.stringResource +import androidx.navigation.NavGraph.Companion.findStartDestination +import androidx.navigation.NavHostController +import androidx.navigation.compose.currentBackStackEntryAsState + + +@Composable +fun BottomNavigationBar(navController: NavHostController) { + val items = listOf( + AppScreen.Main.Tasks, + AppScreen.Main.Events, + AppScreen.Main.Subjects, + AppScreen.Main.Profile, + ) + + NavigationBar { + val navBackStackEntry by navController.currentBackStackEntryAsState() + val currentRoute = navBackStackEntry?.destination?.route + + items.forEach { screen -> + val selected = currentRoute == screen.route + + NavigationBarItem( + selected = selected, + onClick = { + if (!selected) { + navController.navigate(screen.route) { + popUpTo(navController.graph.findStartDestination().id) { + saveState = true + } + launchSingleTop = true + restoreState = true + } + } + }, + icon = { + Icon( + imageVector = if (selected) screen.selectedIcon!! else screen.unselectedIcon!!, + contentDescription = stringResource(id = screen.title!!) + ) + }, + label = { + Text(text = stringResource(id = screen.title!!)) + } + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/navigation/FirstStepNavGraph.kt b/app/src/main/java/com/diegocayo/organizame/presentation/navigation/FirstStepNavGraph.kt new file mode 100644 index 0000000..7712dfa --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/navigation/FirstStepNavGraph.kt @@ -0,0 +1,30 @@ +package com.diegocayo.organizame.presentation.navigation + +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.composable +import androidx.navigation.navigation +import com.diegocayo.organizame.presentation.features.welcome.firstStep.FirstStepScreen +import com.diegocayo.organizame.presentation.features.welcome.grettings.GrettingScreen + +fun NavGraphBuilder.firstStepNavGraph(navController: NavHostController) { + navigation( + startDestination = AppScreen.Welcome.FirstSteps.route, + route = AppScreen.Welcome.route + ) { + composable(route = AppScreen.Welcome.FirstSteps.route) { + FirstStepScreen(navController) + } + + composable( + route = AppScreen.Welcome.Gretting.route, + arguments = AppScreen.Welcome.Gretting.arguments + ) { backStackEntry -> + val name = backStackEntry.arguments?.getString("name") ?: "" + GrettingScreen( + name = name, + navController = navController + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/navigation/MainNavGraph.kt b/app/src/main/java/com/diegocayo/organizame/presentation/navigation/MainNavGraph.kt new file mode 100644 index 0000000..d536942 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/navigation/MainNavGraph.kt @@ -0,0 +1,50 @@ +package com.diegocayo.organizame.presentation.navigation + +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavHostController +import androidx.navigation.compose.composable +import androidx.navigation.navigation +import com.diegocayo.organizame.presentation.features.main.events.create.CreateEventScreen +import com.diegocayo.organizame.presentation.features.main.events.list.EventsListScreen +import com.diegocayo.organizame.presentation.features.main.profile.ProfileScreen +import com.diegocayo.organizame.presentation.features.main.subjects.create.CreateSubjectScreen +import com.diegocayo.organizame.presentation.features.main.subjects.list.SubjectsListScreen +import com.diegocayo.organizame.presentation.features.main.tasks.create.CreateTaskScreen +import com.diegocayo.organizame.presentation.features.main.tasks.list.TasksListScreen + +fun NavGraphBuilder.mainNavGraph(navController: NavHostController) { + navigation( + startDestination = AppScreen.Main.Tasks.route, + route = AppScreen.Main.route + ) { + composable(route = AppScreen.Main.Tasks.route) { + TasksListScreen(navController = navController) + } + composable(route = AppScreen.Main.Tasks.Create.route) { + CreateTaskScreen( + onNavigateBack = { navController.popBackStack() } + ) + } + + composable(route = AppScreen.Main.Events.route) { + EventsListScreen(navController = navController) + } + composable(route = AppScreen.Main.Events.Create.route) { + CreateEventScreen( + onNavigateBack = { navController.popBackStack() } + ) + } + + // Subjects Navigation + composable(route = AppScreen.Main.Subjects.route) { + SubjectsListScreen(navController = navController) + } + composable(route = AppScreen.Main.Subjects.Create.route) { + CreateSubjectScreen( + onNavigateBack = { navController.popBackStack() } + ) + } + + composable(route = AppScreen.Main.Profile.route) { ProfileScreen(navController) } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/navigation/NavGraph.kt b/app/src/main/java/com/diegocayo/organizame/presentation/navigation/NavGraph.kt new file mode 100644 index 0000000..55dc6d5 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/navigation/NavGraph.kt @@ -0,0 +1,38 @@ +package com.diegocayo.organizame.presentation.navigation + +import androidx.compose.runtime.Composable +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import com.diegocayo.organizame.presentation.features.main.events.create.CreateEventScreen +import com.diegocayo.organizame.presentation.features.main.events.list.EventsListScreen +import com.diegocayo.organizame.presentation.features.main.tasks.create.CreateTaskScreen +import com.diegocayo.organizame.presentation.features.main.tasks.list.TasksListScreen + +@Composable +fun NavGraph(navController: NavHostController) { + NavHost( + navController = navController, + startDestination = AppScreen.Main.Tasks.route + ) { + composable(AppScreen.Main.Tasks.route) { + TasksListScreen(navController) + } + + composable(AppScreen.Main.Tasks.Create.route) { + CreateTaskScreen( + onNavigateBack = { navController.popBackStack() } + ) + } + + composable(AppScreen.Main.Events.route) { + EventsListScreen(navController) + } + + composable(AppScreen.Main.Events.Create.route) { + CreateEventScreen( + onNavigateBack = { navController.popBackStack() } + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/navigation/RootNavHost.kt b/app/src/main/java/com/diegocayo/organizame/presentation/navigation/RootNavHost.kt new file mode 100644 index 0000000..303562a --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/navigation/RootNavHost.kt @@ -0,0 +1,43 @@ +package com.diegocayo.organizame.presentation.navigation + +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.currentBackStackEntryAsState +import androidx.navigation.compose.rememberNavController + +@Composable +fun RootNavHost(isAuthenticated: Boolean) { + val navController = rememberNavController() + val showBottomBar = rememberSaveable { mutableStateOf(isAuthenticated) } + val navBackStackEntry by navController.currentBackStackEntryAsState() + val currentRoute = navBackStackEntry?.destination?.route + + showBottomBar.value = currentRoute in listOf( + AppScreen.Main.Tasks.route, + AppScreen.Main.Events.route, + AppScreen.Main.Subjects.route, + AppScreen.Main.Profile.route + ) + + Scaffold( + bottomBar = { + if (showBottomBar.value) { + BottomNavigationBar(navController) + } + } + ) { innerPadding -> + NavHost( + navController = navController, + startDestination = if (isAuthenticated) AppScreen.Main.route else AppScreen.Welcome.route, + modifier = androidx.compose.ui.Modifier.padding(innerPadding) + ) { + firstStepNavGraph(navController) + mainNavGraph(navController) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/theme/Color.kt b/app/src/main/java/com/diegocayo/organizame/presentation/theme/Color.kt new file mode 100644 index 0000000..8b9e91f --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/theme/Color.kt @@ -0,0 +1,11 @@ +package com.diegocayo.organizame.presentation.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/theme/Theme.kt b/app/src/main/java/com/diegocayo/organizame/presentation/theme/Theme.kt new file mode 100644 index 0000000..1034313 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/theme/Theme.kt @@ -0,0 +1,58 @@ +package com.diegocayo.organizame.presentation.theme + + +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun OrganizaMeTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/presentation/theme/Type.kt b/app/src/main/java/com/diegocayo/organizame/presentation/theme/Type.kt new file mode 100644 index 0000000..c3cb52a --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/presentation/theme/Type.kt @@ -0,0 +1,19 @@ +package com.diegocayo.organizame.presentation.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + +) \ No newline at end of file diff --git a/app/src/main/java/com/diegocayo/organizame/utils/moshi/MoshiParser.kt b/app/src/main/java/com/diegocayo/organizame/utils/moshi/MoshiParser.kt new file mode 100644 index 0000000..9f314f2 --- /dev/null +++ b/app/src/main/java/com/diegocayo/organizame/utils/moshi/MoshiParser.kt @@ -0,0 +1,17 @@ +package com.diegocayo.organizame.utils.moshi + +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.Moshi + +class MoshiParser(private val moshi: Moshi) { + + fun toJson(data: T, type: Class): String { + val adapter: JsonAdapter = moshi.adapter(type) + return adapter.toJson(data) + } + + fun fromJson(json: String, type: Class): T? { + val adapter: JsonAdapter = moshi.adapter(type) + return adapter.fromJson(json) + } +} \ No newline at end of file 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..ae24284 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file 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..00f9eaa --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file 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..00f9eaa --- /dev/null +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000..45259c6 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000..6b00aca Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 0000000..25ac866 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 0000000..4821d86 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000..b930f74 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 0000000..fed4c24 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000..e036e4c Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000..8676349 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..08ea127 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 0000000..41f41e3 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000..529506d Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..0f46009 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000..c925fa7 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000..4cc8727 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000..75ebc00 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml new file mode 100644 index 0000000..420e35a --- /dev/null +++ b/app/src/main/res/values-es-rES/strings.xml @@ -0,0 +1,52 @@ + + + OrganizaMe + Tareas + Eventos + Asignaturas + Perfil + Hecho + Pendiente + Nueva Tarea + Título + Descripción + Fecha programada + Sin asignatura + Prioridad + Alta + Media + Baja + Crear tarea + Nuevo evento + Fecha + Hora de inicio + Hora de fin + Crear evento + No hay asignaturas + Nombre + Apellido + Abreviatura + Color + Guardar + Editar perfil + Eliminar cuenta + Fecha de nacimiento + Siguiente + ¿Cuál es tu nombre? + ¿Cuál es tu apellidos? + Atrás + ¿Cuál es tu fecha de nacimiento? + Finalizar + Día + Mes + Año + Todos los campos de la fecha son obligatorios + El año no puede ser posterior al actual + La fecha no puede ser posterior a la actual + La fecha no es válida + ¿Estás seguro de que deseas eliminar tu cuenta? Esta acción no se puede deshacer. + No, cancelar + Si, eliminar + Confirmar eliminación + El título es obligatorio + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100644 index 0000000..f8c6127 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..3bab1ea --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,51 @@ + + OrganizaMe + Tasks + Events + Subjects + Profile + Done + Pending + New task + Title + Description + Scheduled date + No subject + Priority + High + Medium + Low + Create task + New event + Date + Start time + End time + Create event + No subjects + Name + Surname + Abbreviation + Color + Save + Edit profile + Delete account + Date of birth + Next + What is your name? + What is your surname? + Back + What is your Date of birth? + Complete + Day + Month + Year + All date fields are mandatory + The year cannot be later than the current year + The date cannot be later than the current date + The date is not valid + Are you sure you want to delete your account? This action cannot be undone. + No, cancel + Yes, delete + Confirm deletion + The title is compulsory + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 0000000..c9071c6 --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + +