From f6b1c69edcfad903f2cf40cfba8b5d854099c21e Mon Sep 17 00:00:00 2001 From: darken Date: Tue, 24 Feb 2026 20:33:54 +0100 Subject: [PATCH] fix(profiles): Pass profileId from NavKey and reset state on exit Navigation 3 doesn't auto-populate SavedStateHandle from NavKey args like Navigation 2.x did. Pass profileId explicitly from the entry lambda through the ScreenHost to the ViewModel via initialize(). Reset initialized flag on every exit path so re-entering a profile reloads fresh data from the repository. --- .../DeviceProfileCreationNavigation.kt | 4 ++- .../creation/DeviceProfileCreationScreen.kt | 7 +++- .../DeviceProfileCreationViewModel.kt | 35 ++++++++++++------- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/eu/darken/capod/profiles/ui/creation/DeviceProfileCreationNavigation.kt b/app/src/main/java/eu/darken/capod/profiles/ui/creation/DeviceProfileCreationNavigation.kt index fdac8ed2..abe23d1d 100644 --- a/app/src/main/java/eu/darken/capod/profiles/ui/creation/DeviceProfileCreationNavigation.kt +++ b/app/src/main/java/eu/darken/capod/profiles/ui/creation/DeviceProfileCreationNavigation.kt @@ -13,7 +13,9 @@ import javax.inject.Inject class DeviceProfileCreationNavigation @Inject constructor() : NavigationEntry { override fun EntryProviderScope.setup() { - entry { DeviceProfileCreationScreenHost() } + entry { key -> + DeviceProfileCreationScreenHost(profileId = key.profileId) + } } @Module diff --git a/app/src/main/java/eu/darken/capod/profiles/ui/creation/DeviceProfileCreationScreen.kt b/app/src/main/java/eu/darken/capod/profiles/ui/creation/DeviceProfileCreationScreen.kt index 271cc4a3..b38315fe 100644 --- a/app/src/main/java/eu/darken/capod/profiles/ui/creation/DeviceProfileCreationScreen.kt +++ b/app/src/main/java/eu/darken/capod/profiles/ui/creation/DeviceProfileCreationScreen.kt @@ -58,7 +58,12 @@ import eu.darken.capod.common.toHex import eu.darken.capod.pods.core.PodDevice @Composable -fun DeviceProfileCreationScreenHost(vm: DeviceProfileCreationViewModel = hiltViewModel()) { +fun DeviceProfileCreationScreenHost( + profileId: String? = null, + vm: DeviceProfileCreationViewModel = hiltViewModel(), +) { + LaunchedEffect(Unit) { vm.initialize(profileId) } + ErrorEventHandler(vm) NavigationEventHandler(vm) diff --git a/app/src/main/java/eu/darken/capod/profiles/ui/creation/DeviceProfileCreationViewModel.kt b/app/src/main/java/eu/darken/capod/profiles/ui/creation/DeviceProfileCreationViewModel.kt index f0c806eb..71de003a 100644 --- a/app/src/main/java/eu/darken/capod/profiles/ui/creation/DeviceProfileCreationViewModel.kt +++ b/app/src/main/java/eu/darken/capod/profiles/ui/creation/DeviceProfileCreationViewModel.kt @@ -1,7 +1,6 @@ package eu.darken.capod.profiles.ui.creation import android.content.Context -import androidx.lifecycle.SavedStateHandle import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext import eu.darken.capod.R @@ -43,15 +42,15 @@ private data class ProfileEditorState( @HiltViewModel class DeviceProfileCreationViewModel @Inject constructor( @ApplicationContext private val context: Context, - handle: SavedStateHandle, dispatcherProvider: DispatcherProvider, private val deviceProfilesRepo: DeviceProfilesRepo, private val bluetoothManager: BluetoothManager2, private val webpageTool: WebpageTool, ) : ViewModel4(dispatcherProvider) { - private val profileId: ProfileId? = handle.get("profileId") - private val isEditMode: Boolean = profileId != null + private var profileId: ProfileId? = null + private var isEditMode: Boolean = false + private var initialized = false private val _currentState = MutableStateFlow(ProfileEditorState()) private val _initialState = MutableStateFlow(ProfileEditorState()) @@ -60,7 +59,13 @@ class DeviceProfileCreationViewModel @Inject constructor( val showUnsavedChangesEvent = SingleEventFlow() val showDeleteConfirmationEvent = SingleEventFlow() - init { + fun initialize(profileId: String?) { + if (initialized && this.profileId == profileId) return + initialized = true + + this.profileId = profileId + this.isEditMode = profileId != null + if (isEditMode && profileId != null) { loadProfile(profileId) } else { @@ -161,12 +166,17 @@ class DeviceProfileCreationViewModel @Inject constructor( fun hasUnsavedChanges(): Boolean = _currentState.value != _initialState.value + private fun exitScreen() { + initialized = false + navUp() + } + fun onBackPressed() { log(TAG) { "onBackPressed()" } if (hasUnsavedChanges()) { showUnsavedChangesEvent.tryEmit(Unit) } else { - navUp() + exitScreen() } } @@ -204,7 +214,7 @@ class DeviceProfileCreationViewModel @Inject constructor( deviceProfilesRepo.addProfile(profile) log(TAG) { "Profile created: $profile" } } - navUp() + exitScreen() } catch (e: Exception) { log(TAG) { "Failed to save profile: $e" } errorEvents.emitBlocking(e) @@ -218,12 +228,13 @@ class DeviceProfileCreationViewModel @Inject constructor( } fun deleteProfile() { - if (isEditMode && profileId != null) { + val id = profileId + if (isEditMode && id != null) { launch { try { - deviceProfilesRepo.removeProfile(profileId) - log(TAG) { "Profile deleted: $profileId" } - navUp() + deviceProfilesRepo.removeProfile(id) + log(TAG) { "Profile deleted: $id" } + exitScreen() } catch (e: Exception) { log(TAG) { "Failed to delete profile: $e" } errorEvents.emitBlocking(e) @@ -234,7 +245,7 @@ class DeviceProfileCreationViewModel @Inject constructor( fun discardChanges() { log(TAG) { "discardChanges()" } - navUp() + exitScreen() } fun openKeyGuide() {