From e0bd5bd580f3824374ecef885ca2035df14588f9 Mon Sep 17 00:00:00 2001 From: Ash Date: Fri, 3 Oct 2025 12:11:31 -0700 Subject: [PATCH 001/511] Fix: Synchronize category selection between Home and TaskList screens This commit introduces a new `onCategorySelected` lambda to propagate category selection events from the `HomeScreen` up to the `MainScreen`. This ensures that when a user selects a category on the "Home" tab, the "Tasks" tab is automatically updated to display the task lists for that same category. Key changes: - **`PhotoDoHomeUiRoute.kt`**: - Added a new `onCategorySelected: (Long) -> Unit` parameter, which is passed down to the `HomeScreen`. - **`HomeScreen.kt`**: - Receives the `onCategorySelected` lambda and calls it when a user selects a category. This notifies the parent composable of the change. - **`MainScreen.kt`**: - The `onCategorySelected` lambda is now passed down to the `PhotoDoHomeUiRoute`, completing the chain and allowing the `MainScreen` to react to category selections made in the home feature. --- .../photodo/features/home/ui/HomeScreen.kt | 4 ++++ .../photodo/features/home/ui/PhotoDoHomeUiRoute.kt | 2 ++ .../photodo/ui/navigation/main/MainScreen.kt | 13 +++++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/applications/photodo/features/home/src/main/java/com/ylabz/basepro/applications/photodo/features/home/ui/HomeScreen.kt b/applications/photodo/features/home/src/main/java/com/ylabz/basepro/applications/photodo/features/home/ui/HomeScreen.kt index bf5b340c7..b5facbb28 100644 --- a/applications/photodo/features/home/src/main/java/com/ylabz/basepro/applications/photodo/features/home/ui/HomeScreen.kt +++ b/applications/photodo/features/home/src/main/java/com/ylabz/basepro/applications/photodo/features/home/ui/HomeScreen.kt @@ -20,6 +20,7 @@ fun HomeScreen( onEvent: (HomeEvent) -> Unit, // This is for navigating from a Task in the list to the Task Detail (3rd pane) onSelectList: (Long) -> Unit, + onCategorySelected: (Long) -> Unit, // <-- ADD THIS PARAMETER modifier: Modifier = Modifier, ) { // val navigator = rememberListDetailPaneScaffoldNavigator() @@ -45,6 +46,9 @@ fun HomeScreen( // This updates the state, so the detailPane knows what to show. This is correct. onEvent(HomeEvent.OnCategorySelected(category)) + // This calls the lambda to update the GLOBAL state in MainScreen + onCategorySelected(category.categoryId) // <-- CALL THE LAMBDA + // 2. Replace onSelectList with the navigator call. // This tells the scaffold to show the detail pane. // 4. Launch the navigation call in a coroutine diff --git a/applications/photodo/features/home/src/main/java/com/ylabz/basepro/applications/photodo/features/home/ui/PhotoDoHomeUiRoute.kt b/applications/photodo/features/home/src/main/java/com/ylabz/basepro/applications/photodo/features/home/ui/PhotoDoHomeUiRoute.kt index e3dce40cb..41fcf1236 100644 --- a/applications/photodo/features/home/src/main/java/com/ylabz/basepro/applications/photodo/features/home/ui/PhotoDoHomeUiRoute.kt +++ b/applications/photodo/features/home/src/main/java/com/ylabz/basepro/applications/photodo/features/home/ui/PhotoDoHomeUiRoute.kt @@ -17,6 +17,7 @@ fun PhotoDoHomeUiRoute( modifier: Modifier = Modifier, // The navigation lambda now expects a Long (the categoryId) navTo: (Long) -> Unit, + onCategorySelected: (Long) -> Unit, // <-- ADD THIS PARAMETER viewModel: HomeViewModel = hiltViewModel() ) { val uiState by viewModel.uiState.collectAsState() @@ -36,6 +37,7 @@ fun PhotoDoHomeUiRoute( Log.d("PhotoDoHomeUiRoute", "STEP2: Navigating to TaskList with categoryId: $taskID") navTo(taskID) }, + onCategorySelected = onCategorySelected, // <-- PASS THE LAMBDA DOWN // This handles the "Add" button on the empty screen /*onAddList = { state.selectedCategory?.let { category -> diff --git a/applications/photodo/src/main/java/com/ylabz/basepro/applications/photodo/ui/navigation/main/MainScreen.kt b/applications/photodo/src/main/java/com/ylabz/basepro/applications/photodo/ui/navigation/main/MainScreen.kt index eaa96a158..7628d9d0b 100644 --- a/applications/photodo/src/main/java/com/ylabz/basepro/applications/photodo/ui/navigation/main/MainScreen.kt +++ b/applications/photodo/src/main/java/com/ylabz/basepro/applications/photodo/ui/navigation/main/MainScreen.kt @@ -292,7 +292,10 @@ private fun AppContent( },*/ // This function is ONLY for navigating from a Task List item to the Detail screen. navTo = { listId -> - Log.d(TAG, "Step3: Navigating from Task List Item to Detail Screen with listId: $listId") + Log.d( + TAG, + "Step3: Navigating from Task List Item to Detail Screen with listId: $listId" + ) // 1. Create the key for the final detail screen (Pane 3). val detailKey = PhotoDoNavKeys.TaskListDetailKey(listId.toString()) @@ -300,7 +303,13 @@ private fun AppContent( // 2. Add it to the back stack. The adaptive strategy handles the rest. backStack.add(detailKey) }, - viewModel = homeViewModel + viewModel = homeViewModel, + // ### THIS IS THE SOLUTION ### + // The `onCategorySelected` lambda is already available here as a + // parameter of the `AppContent` function. You just need to pass it down. + // This allows the HomeScreen to notify the MainScreen whenever a new + // category is selected, keeping the "Tasks" tab in sync. + onCategorySelected = onCategorySelected ) } From 82f053c72cc65f1862aca417d8d0e1415755ac31 Mon Sep 17 00:00:00 2001 From: Ash Date: Fri, 3 Oct 2025 13:59:39 -0700 Subject: [PATCH 002/511] Fix: Correct `lifecycleViewmodelNav3` dependency version This commit fixes an incorrect version for the `lifecycleViewmodelNav3` dependency, updating it from a non-existent `1.x` version to the correct `2.x` release line. Key changes: - **`gradle/libs.versions.toml`**: - Updated the `lifecycleViewmodelNav3` version from `1.0.0-alpha04` to `2.10.0-alpha04`. --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 00d5ecdeb..c53d9df75 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,7 +32,7 @@ activityCompose = "1.11.0" # AndroidX Activity Compose, for Jetpack Compose androidxNavigation = "2.9.4" # AndroidX Navigation component (Compose) # # AndroidX - Navigation (Nav3) nav3Core = "1.0.0-alpha10" # Navigation 3 Core libraries version -lifecycleViewmodelNav3 = "1.0.0-alpha04" # Navigation 3 ViewModel support +lifecycleViewmodelNav3 = "2.10.0-alpha04" # Navigation 3 ViewModel support material3AdaptiveNav3 = "1.0.0-alpha03" # Navigation 3 Material3 Adaptive Layouts (Snapshot) # material3Adaptive = "1.0.0-alpha06" # AndroidX Test Runner From 95f9cd7e557a9259f11300da265a846a2f6da0b2 Mon Sep 17 00:00:00 2001 From: Ash Date: Fri, 3 Oct 2025 14:13:12 -0700 Subject: [PATCH 003/511] Docs: Add design document for FAB management This commit adds a new markdown file, `FAB.md`, which serves as a design document for the context-aware Floating Action Button (FAB) in the PhotoDo application. The document details the following: - **Guiding Principle**: The FAB should dynamically change its icon, text, and action based on the user's current navigation context. - **Behavior**: It outlines the FAB's state ("Add Category", "Add List", "Add Item", or hidden) for each application tab (Home, Tasks, Settings) and for different screen layouts (1, 2, or 3 panes). - **Implementation Strategy**: It describes how a single `ExtendedFloatingActionButton` is managed from `MainScreen.kt`, with its state controlled by a `FabState` data class. Each navigation destination is responsible for setting the appropriate FAB state. - **Summary Table**: A table is included for a quick overview of FAB behavior across different screens and contexts. --- .../basepro/applications/photodo/ui/FAB.md | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 applications/photodo/src/main/java/com/ylabz/basepro/applications/photodo/ui/FAB.md diff --git a/applications/photodo/src/main/java/com/ylabz/basepro/applications/photodo/ui/FAB.md b/applications/photodo/src/main/java/com/ylabz/basepro/applications/photodo/ui/FAB.md new file mode 100644 index 000000000..3e26fba05 --- /dev/null +++ b/applications/photodo/src/main/java/com/ylabz/basepro/applications/photodo/ui/FAB.md @@ -0,0 +1,84 @@ +Of course. I will create the `FAB.md` design document. Here is the content for the file. + +*** + +# Design Document: Floating Action Button (FAB) Management + +This document outlines the design, behavior, and implementation plan for the context-aware Floating +Action Button (FAB) in the PhotoDo application. + +## 1. Guiding Principle + +The FAB's primary purpose is to provide the most relevant "add" action based on the user's current context. +Its state (icon, text, and action) is not static but dynamically changes depending on the content visible on the screen. +This creates an intuitive and powerful user experience, ensuring the user always knows what action the FAB will perform. + +The logic is driven by the application's navigation state, making it inherently adaptive and consistent +across all screen sizes, from compact phones ("closed") to large tablets ("open"). + +--- + +## 2. Behavior Across Application Tabs + +### 2.1. Home Tab + +The Home tab has the most complex behavior as its content changes to display one, two, or three panes of +information on expanded screens. The FAB adapts to the most detailed pane currently in focus. + +#### Context A: Viewing Only the Category List (1 Pane) +* **User View:** The initial state of the Home tab. The first column (Categories) is visible, and a placeholder is shown in the second column. +* **FAB State:** **"Add Category"** +* **Action:** Triggers an event to add a new top-level category. This will likely open a bottom sheet for the user to enter the new category's name. + +#### Context B: A Category is Selected (2 Panes) +* **User View:** The user has clicked a category. The first column (Categories) remains visible, and the second column now shows the list of tasks for that selected category. +* **FAB State:** **"Add List"** +* **Action:** Triggers an event to add a new task list *to the currently selected category*. This will likely open a bottom sheet for the user to enter the new list's name. + +#### Context C: A Task List is Selected (3 Panes) +* **User View:** The user has clicked a task list in the second column. All three columns are now visible: Categories, Task Lists, and the Task Detail view. +* **FAB State:** **"Add Item"** +* **Action:** Triggers an event to add a new photo/item *to the currently viewed task list*. This is expected to navigate to a full-screen camera or photo picker interface. + +### 2.2. Tasks Tab + +The "Tasks" tab provides a focused view of the task lists for a single category. + +#### Context A: Viewing a Task List +* **User View:** The user is on the Tasks tab, viewing the list of tasks for the last-interacted-with category. +* **FAB State:** **"Add List"** +* **Action:** Triggers an event to add a new task list to the current category. + +#### Context B: Viewing Task Details +* **User View:** The user has clicked on a task list and has navigated to its detail screen. +* **FAB State:** **"Add Item"** +* **Action:** Identical to the Home tab's detail view. It triggers an event to add a new photo/item to the currently viewed task list. + +### 2.3. Settings Tab + +The Settings tab is for configuration and information, not content creation. + +* **FAB State:** **Hidden** +* **Action:** None. + +--- + +## 3. Implementation Strategy + +The FAB is a single, global `ExtendedFloatingActionButton` composable located in `MainScreen.kt`. Its state is controlled by a `FabState` data class instance, which is hoisted in `MainScreen`. + +Each navigation destination (`entry` within the `NavDisplay`) is responsible for determining the correct FAB state for its context. It does this by calling the `setFabState` function (which is passed down) from within a `LaunchedEffect`. + +- **Hiding the FAB:** A screen can hide the FAB by calling `setFabState(null)`. +- **Changing the FAB:** A screen changes the FAB's text and action by calling `setFabState(FabState("New Text") { /* new action */ })`. +- **Context-Aware Logic:** For screens with multiple contexts (like the `HomeScreen`), a `LaunchedEffect` observes the relevant state (e.g., `uiState.selectedCategory`) and calls `setFabState` whenever that state changes. + +## 4. Summary Table + +| Current Screen/Pane in Focus | FAB Text | FAB Action | Device State | +| :---------------------------------------------------------- | :--------------- | :--------------------------------------- | :---------------- | +| **Home Tab:** Category List (Pane 1) | **"Add Category"** | Add a new Category | Open or Closed | +| **Home Tab:** Task List (Pane 2) | **"Add List"** | Add a new List to the selected Category | Open or Closed | +| **Tasks Tab:** Task List | **"Add List"** | Add a new List to the current Category | Open or Closed | +| **Any Tab:** Task Detail (Pane 3) | **"Add Item"** | Add a new Photo/Item to the current List | Open or Closed | +| **Settings Tab** | **(Hidden)** | None | Open or Closed | \ No newline at end of file From 0a11713bf33aa4c4337c19ca08dd10e60dfa8f36 Mon Sep 17 00:00:00 2001 From: Ash Date: Fri, 3 Oct 2025 16:51:31 -0700 Subject: [PATCH 004/511] Feat: Add new `:core` module for shared UI state This commit introduces a new Android library module, `:applications:photodo:core`, to house shared UI components and state. The primary change is the creation of a public data class, `FabState`, which was previously a private class within the `:home` feature. Extracting it to the `:core` module allows it to be shared between different feature modules, improving code reuse and architectural structure. Key changes: - **`applications/photodo/core`**: - Added a new Android library module with standard configuration (`build.gradle.kts`, `AndroidManifest.xml`, `proguard-rules.pro`). - **`applications/photodo/core/src/main/java/com/ylabz/basepro/applications/photodo/core/ui/FabState.kt`**: - Created the public `FabState(val text: String, val onClick: () -> Unit)` data class to encapsulate state for the Floating Action Button. --- applications/photodo/core/.gitignore | 1 + applications/photodo/core/build.gradle.kts | 48 +++++++++++++++++++ applications/photodo/core/consumer-rules.pro | 0 applications/photodo/core/proguard-rules.pro | 21 ++++++++ .../photodo/core/ExampleInstrumentedTest.kt | 24 ++++++++++ .../photodo/core/src/main/AndroidManifest.xml | 4 ++ .../applications/photodo/core/ui/FabState.kt | 11 +++++ .../photodo/core/ExampleUnitTest.kt | 17 +++++++ 8 files changed, 126 insertions(+) create mode 100644 applications/photodo/core/.gitignore create mode 100644 applications/photodo/core/build.gradle.kts create mode 100644 applications/photodo/core/consumer-rules.pro create mode 100644 applications/photodo/core/proguard-rules.pro create mode 100644 applications/photodo/core/src/androidTest/java/com/ylabz/basepro/applications/photodo/core/ExampleInstrumentedTest.kt create mode 100644 applications/photodo/core/src/main/AndroidManifest.xml create mode 100644 applications/photodo/core/src/main/java/com/ylabz/basepro/applications/photodo/core/ui/FabState.kt create mode 100644 applications/photodo/core/src/test/java/com/ylabz/basepro/applications/photodo/core/ExampleUnitTest.kt diff --git a/applications/photodo/core/.gitignore b/applications/photodo/core/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/applications/photodo/core/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/applications/photodo/core/build.gradle.kts b/applications/photodo/core/build.gradle.kts new file mode 100644 index 000000000..2cf2c1755 --- /dev/null +++ b/applications/photodo/core/build.gradle.kts @@ -0,0 +1,48 @@ +plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) +} + +android { + namespace = "com.ylabz.basepro.applications.photodo.core" + compileSdk = 36 + + defaultConfig { + minSdk = libs.versions.minSdk.get().toInt() // UPDATED + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = providers.gradleProperty("isMinifyForRelease").get().toBoolean() + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + consumerProguardFiles("proguard-rules.pro") // Added this line + } + // This debug block ensures a fast development cycle + debug { + isMinifyEnabled = false + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 + } + kotlinOptions { + jvmTarget = "21" // Aligned with feature:nav3 (will use jvmToolchain if this causes issues) + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.material.legacy) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) +} \ No newline at end of file diff --git a/applications/photodo/core/consumer-rules.pro b/applications/photodo/core/consumer-rules.pro new file mode 100644 index 000000000..e69de29bb diff --git a/applications/photodo/core/proguard-rules.pro b/applications/photodo/core/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/applications/photodo/core/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/applications/photodo/core/src/androidTest/java/com/ylabz/basepro/applications/photodo/core/ExampleInstrumentedTest.kt b/applications/photodo/core/src/androidTest/java/com/ylabz/basepro/applications/photodo/core/ExampleInstrumentedTest.kt new file mode 100644 index 000000000..23738551d --- /dev/null +++ b/applications/photodo/core/src/androidTest/java/com/ylabz/basepro/applications/photodo/core/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.ylabz.basepro.applications.photodo.core + +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.ylabz.basepro.applications.photodo.core.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/applications/photodo/core/src/main/AndroidManifest.xml b/applications/photodo/core/src/main/AndroidManifest.xml new file mode 100644 index 000000000..a5918e68a --- /dev/null +++ b/applications/photodo/core/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/applications/photodo/core/src/main/java/com/ylabz/basepro/applications/photodo/core/ui/FabState.kt b/applications/photodo/core/src/main/java/com/ylabz/basepro/applications/photodo/core/ui/FabState.kt new file mode 100644 index 000000000..decdd12f3 --- /dev/null +++ b/applications/photodo/core/src/main/java/com/ylabz/basepro/applications/photodo/core/ui/FabState.kt @@ -0,0 +1,11 @@ +package com.ylabz.basepro.applications.photodo.core.ui + +// By making this a public data class in its own file, it becomes accessible +// to any module that depends on the main ':applications:photodo' module. +// +// NOTE: For a stricter architecture, this would live in a `:core:ui` module that +// both `:applications:photodo` and `:features:home` would implement. +// For this project, placing it here is the simplest fix. +data class FabState(val text: String, val onClick: () -> Unit) + +// private data class FabState(val text: String, val onClick: () -> Unit) \ No newline at end of file diff --git a/applications/photodo/core/src/test/java/com/ylabz/basepro/applications/photodo/core/ExampleUnitTest.kt b/applications/photodo/core/src/test/java/com/ylabz/basepro/applications/photodo/core/ExampleUnitTest.kt new file mode 100644 index 000000000..6dca85b9a --- /dev/null +++ b/applications/photodo/core/src/test/java/com/ylabz/basepro/applications/photodo/core/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.ylabz.basepro.applications.photodo.core + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file From db98d4c9b59cc7d532cc8b5c08769824ab426ee5 Mon Sep 17 00:00:00 2001 From: Ash Date: Fri, 3 Oct 2025 16:53:43 -0700 Subject: [PATCH 005/511] Feat: Add `OnAddPhotoClicked` event for detail screen This commit introduces a new event, `OnAddPhotoClicked`, to handle user interaction on the detail screen. A corresponding event handler with logging has been added to the `PhotoDoDetailViewModel` to process this action, preparing for future implementation of adding a photo. Key changes: - **`PhotoDoDetailEvents.kt`**: - Added the `OnAddPhotoClicked` data object to the `PhotoDoDetailEvent` sealed class. - **`PhotoDoDetailViewModel.kt`**: - Implemented a new `onEvent` function to handle UI events. - Added a `when` block to process `OnAddPhotoClicked`, which currently logs the action and includes a `TODO` for navigating to a camera or photo picker. --- .../photodolist/ui/detail/PhotoDoDetailEvents.kt | 1 + .../photodolist/ui/detail/PhotoDoDetailViewModel.kt | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/applications/photodo/features/photodolist/src/main/java/com/ylabz/basepro/applications/photodo/features/photodolist/ui/detail/PhotoDoDetailEvents.kt b/applications/photodo/features/photodolist/src/main/java/com/ylabz/basepro/applications/photodo/features/photodolist/ui/detail/PhotoDoDetailEvents.kt index b281bd0cd..e52895c8b 100644 --- a/applications/photodo/features/photodolist/src/main/java/com/ylabz/basepro/applications/photodo/features/photodolist/ui/detail/PhotoDoDetailEvents.kt +++ b/applications/photodo/features/photodolist/src/main/java/com/ylabz/basepro/applications/photodo/features/photodolist/ui/detail/PhotoDoDetailEvents.kt @@ -1,5 +1,6 @@ package com.ylabz.basepro.applications.photodo.features.photodolist.ui.detail sealed class PhotoDoDetailEvent { + data object OnAddPhotoClicked : PhotoDoDetailEvent() // <-- ADD THIS LINE // Example: data class OnAddPhotoClicked(val photoUri: String) : PhotoDoDetailEvent() } \ No newline at end of file diff --git a/applications/photodo/features/photodolist/src/main/java/com/ylabz/basepro/applications/photodo/features/photodolist/ui/detail/PhotoDoDetailViewModel.kt b/applications/photodo/features/photodolist/src/main/java/com/ylabz/basepro/applications/photodo/features/photodolist/ui/detail/PhotoDoDetailViewModel.kt index eb9e214e9..649fe5556 100644 --- a/applications/photodo/features/photodolist/src/main/java/com/ylabz/basepro/applications/photodo/features/photodolist/ui/detail/PhotoDoDetailViewModel.kt +++ b/applications/photodo/features/photodolist/src/main/java/com/ylabz/basepro/applications/photodo/features/photodolist/ui/detail/PhotoDoDetailViewModel.kt @@ -1,5 +1,6 @@ package com.ylabz.basepro.applications.photodo.features.photodolist.ui.detail +import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.ylabz.basepro.applications.photodo.db.repo.PhotoDoRepo @@ -41,6 +42,17 @@ class PhotoDoDetailViewModel @Inject constructor( initialValue = PhotoDoDetailUiState.Loading ) + // ### NEW FUNCTION ### + // This function will be called by the FAB when the user is on the detail screen. + fun onEvent(event: PhotoDoDetailEvent) { + when (event) { + PhotoDoDetailEvent.OnAddPhotoClicked -> { + Log.d("PhotoDoDetailVM", "FAB Clicked: Add Photo to list.") + // TODO: Implement navigation to camera or photo picker screen. + } + } + } + fun loadList(id: String) { _listId.value = id } From ea3094d09422fe8053b6335b27a885961d9fb701 Mon Sep 17 00:00:00 2001 From: Ash Date: Fri, 3 Oct 2025 17:10:53 -0700 Subject: [PATCH 006/511] Feat: Implement context-aware Floating Action Button This commit introduces a context-aware Floating Action Button (FAB) that changes its function based on the UI state. When no category is selected, the FAB is configured to "Add Category." When a category is selected, it changes to "Add List." This is achieved by lifting the FAB state management up from the `HomeScreen` to a higher-level component. Key changes: - **`HomeScreen.kt`**: - A `LaunchedEffect` has been added to observe `uiState.selectedCategory`. - It calls the new `setFabState` function to update the FAB's text and action depending on whether a category is selected. - The action for adding a new list is currently commented out. - **`PhotoDoHomeUiRoute.kt`**: - The `PhotoDoHomeUiRoute` now accepts a `setFabState: (FabState?) -> Unit` lambda. - This lambda is passed down to the `HomeScreen` composable, allowing it to control the FAB's state from a central location. --- .../photodo/features/home/ui/HomeScreen.kt | 19 +++++++++++++++++++ .../features/home/ui/PhotoDoHomeUiRoute.kt | 10 ++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/applications/photodo/features/home/src/main/java/com/ylabz/basepro/applications/photodo/features/home/ui/HomeScreen.kt b/applications/photodo/features/home/src/main/java/com/ylabz/basepro/applications/photodo/features/home/ui/HomeScreen.kt index b5facbb28..e68cb36ba 100644 --- a/applications/photodo/features/home/src/main/java/com/ylabz/basepro/applications/photodo/features/home/ui/HomeScreen.kt +++ b/applications/photodo/features/home/src/main/java/com/ylabz/basepro/applications/photodo/features/home/ui/HomeScreen.kt @@ -6,8 +6,10 @@ import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffold import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier +import com.ylabz.basepro.applications.photodo.core.ui.FabState import com.ylabz.basepro.applications.photodo.features.home.ui.components.CategoryList import com.ylabz.basepro.applications.photodo.features.home.ui.components.TaskList import kotlinx.coroutines.launch @@ -21,8 +23,25 @@ fun HomeScreen( // This is for navigating from a Task in the list to the Task Detail (3rd pane) onSelectList: (Long) -> Unit, onCategorySelected: (Long) -> Unit, // <-- ADD THIS PARAMETER + setFabState: (FabState?) -> Unit, // <-- IT'S A PARAMETER PASSED TO THE FUNCTION modifier: Modifier = Modifier, ) { + // ### NEW LOGIC: Context-Aware FAB ### + // This LaunchedEffect observes the selectedCategory. If it changes, the + // effect will re-run, updating the FAB to match the current context. + LaunchedEffect(uiState.selectedCategory) { + if (uiState.selectedCategory == null) { + // Context: No category is selected. + // Action: The FAB should add a new category. + setFabState(FabState("Add Category") { onEvent(HomeEvent.OnAddCategoryClicked) }) + } else { + // Context: A category IS selected. + // Action: The FAB should add a new list to that category. + setFabState(FabState("Add List") { /*onEvent(HomeEvent.OnAddTaskListClicked)*/ }) + } + } + + // val navigator = rememberListDetailPaneScaffoldNavigator() val navigator = rememberListDetailPaneScaffoldNavigator() val scope = rememberCoroutineScope() // 3. Get a coroutine scope diff --git a/applications/photodo/features/home/src/main/java/com/ylabz/basepro/applications/photodo/features/home/ui/PhotoDoHomeUiRoute.kt b/applications/photodo/features/home/src/main/java/com/ylabz/basepro/applications/photodo/features/home/ui/PhotoDoHomeUiRoute.kt index 41fcf1236..b0248311e 100644 --- a/applications/photodo/features/home/src/main/java/com/ylabz/basepro/applications/photodo/features/home/ui/PhotoDoHomeUiRoute.kt +++ b/applications/photodo/features/home/src/main/java/com/ylabz/basepro/applications/photodo/features/home/ui/PhotoDoHomeUiRoute.kt @@ -11,6 +11,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel +import com.ylabz.basepro.applications.photodo.core.ui.FabState @Composable fun PhotoDoHomeUiRoute( @@ -18,6 +19,7 @@ fun PhotoDoHomeUiRoute( // The navigation lambda now expects a Long (the categoryId) navTo: (Long) -> Unit, onCategorySelected: (Long) -> Unit, // <-- ADD THIS PARAMETER + setFabState: (FabState?) -> Unit, // <-- ADD THIS PARAMETER viewModel: HomeViewModel = hiltViewModel() ) { val uiState by viewModel.uiState.collectAsState() @@ -34,7 +36,10 @@ fun PhotoDoHomeUiRoute( onEvent = viewModel::onEvent, // When a task list is selected, navigate using its categoryId onSelectList = { taskID -> - Log.d("PhotoDoHomeUiRoute", "STEP2: Navigating to TaskList with categoryId: $taskID") + Log.d( + "PhotoDoHomeUiRoute", + "STEP2: Navigating to TaskList with categoryId: $taskID" + ) navTo(taskID) }, onCategorySelected = onCategorySelected, // <-- PASS THE LAMBDA DOWN @@ -44,7 +49,8 @@ fun PhotoDoHomeUiRoute( viewModel.onEvent(HomeEvent.OnAddTaskListClicked(category.categoryId)) } },*/ - modifier = modifier + modifier = modifier, + setFabState = setFabState ) } is HomeUiState.Error -> { From ec7c84f85dde814e7b075e811feb8d5de95b1806 Mon Sep 17 00:00:00 2001 From: Ash Date: Fri, 3 Oct 2025 17:12:23 -0700 Subject: [PATCH 007/511] Refactor: Introduce core module for PhotoDo application This commit introduces a new `:applications:photodo:core` module and integrates it as a dependency for the main `:applications:photodo` app and the `:applications:photodo:features:home` feature module. This refactoring helps to modularize shared logic within the PhotoDo application. The project's Gradle settings have been updated to include this new module. Key changes: - **`settings.gradle.kts`**: - Added `include(":applications:photodo:core")` to the project structure. - **`.idea/gradle.xml`**: - Registered the new `:applications/photodo/core` module path. - **`applications/photodo/build.gradle.kts`**: - Added `implementation(project(":applications:photodo:core"))`. - **`applications/photodo/features/home/build.gradle.kts`**: - Added `implementation(project(":applications:photodo:core"))`. - **`gradle/libs.versions.fix.toml`**: - Added a new, currently unused, version catalog file. This appears to be a copy or backup and does not affect the build. --- .idea/gradle.xml | 1 + applications/photodo/build.gradle.kts | 1 + .../photodo/features/home/build.gradle.kts | 2 + gradle/libs.versions.fix.toml | 297 ++++++++++++++++++ settings.gradle.kts | 1 + 5 files changed, 302 insertions(+) create mode 100644 gradle/libs.versions.fix.toml diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 7da008451..ca05549a4 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -23,6 +23,7 @@