diff --git a/CHANGELOG.md b/CHANGELOG.md index 917dde40a..f6f41bd4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ Changelog **Unreleased** -------------- +- **Fix**: Fix `rememberRetained` implicitly requiring `LocalContext` where it used to no-op. + 0.22.0 ------ diff --git a/circuit-retained/src/androidInstrumentedTest/kotlin/com/slack/circuit/retained/android/RetainedSaveableTest.kt b/circuit-retained/src/androidInstrumentedTest/kotlin/com/slack/circuit/retained/android/RetainedSaveableTest.kt index a301eaa81..6ee56d228 100644 --- a/circuit-retained/src/androidInstrumentedTest/kotlin/com/slack/circuit/retained/android/RetainedSaveableTest.kt +++ b/circuit-retained/src/androidInstrumentedTest/kotlin/com/slack/circuit/retained/android/RetainedSaveableTest.kt @@ -24,6 +24,7 @@ import com.slack.circuit.retained.Continuity import com.slack.circuit.retained.ContinuityViewModel import com.slack.circuit.retained.LocalCanRetainChecker import com.slack.circuit.retained.LocalRetainedStateRegistry +import com.slack.circuit.retained.NoOpRetainedStateRegistry import com.slack.circuit.retained.continuityRetainedStateRegistry import com.slack.circuit.retained.rememberCanRetainChecker import com.slack.circuit.retained.rememberRetained @@ -125,6 +126,44 @@ class RetainedSaveableTest { composeTestRule.onNodeWithTag("superBigData").assertTextEquals("null") } + @Test + fun saveableIsUsedWhenRetainIsNoop() { + var id = 0 + lateinit var data: CacheableData + + fun setContent() { + scenario.onActivity { activity -> + activity.setContent { + CompositionLocalProvider(LocalRetainedStateRegistry provides NoOpRetainedStateRegistry) { + data = rememberRetained(saver = CacheableData.Saver) { CacheableData(id++) } + Text(modifier = Modifier.testTag("id"), text = "${data.id}") + Text(modifier = Modifier.testTag("superBigData"), text = "${data.superBigData}") + } + } + } + } + + setContent() + + // Check initial state is correct + composeTestRule.onNodeWithTag("id").assertTextEquals("0") + composeTestRule.onNodeWithTag("superBigData").assertTextEquals("null") + + data.superBigData = "Super big data" + composeTestRule.waitForIdle() + + composeTestRule.onNodeWithTag("id").assertTextEquals("0") + composeTestRule.onNodeWithTag("superBigData").assertTextEquals("Super big data") + + scenario.recreate() + + setContent() + + // Retained state is not preserved, but id is + composeTestRule.onNodeWithTag("id").assertTextEquals("0") + composeTestRule.onNodeWithTag("superBigData").assertTextEquals("null") + } + private fun setActivityContent(content: @Composable () -> Unit) { scenario.onActivity { activity -> activity.setContent { diff --git a/circuit-retained/src/commonMain/kotlin/com/slack/circuit/retained/RememberRetained.kt b/circuit-retained/src/commonMain/kotlin/com/slack/circuit/retained/RememberRetained.kt index ccd44e96a..deaf7f5f2 100644 --- a/circuit-retained/src/commonMain/kotlin/com/slack/circuit/retained/RememberRetained.kt +++ b/circuit-retained/src/commonMain/kotlin/com/slack/circuit/retained/RememberRetained.kt @@ -17,6 +17,7 @@ import androidx.compose.runtime.saveable.SaveableStateRegistry import androidx.compose.runtime.saveable.Saver import androidx.compose.runtime.saveable.SaverScope import androidx.compose.runtime.saveable.autoSaver +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.snapshots.SnapshotMutableState import androidx.compose.runtime.structuralEqualityPolicy @@ -144,7 +145,10 @@ public fun rememberRetained( ): T { val saveableStateRegistry = LocalSaveableStateRegistry.current val retainedStateRegistry = LocalRetainedStateRegistry.current - + // Short-circuit no-ops + if (retainedStateRegistry === NoOpRetainedStateRegistry) { + return rememberSaveable(inputs = inputs, saver = saver, init = init) + } val compositeKey = currentCompositeKeyHash // key is the one provided by the user or the one generated by the compose runtime val finalKey =