Skip to content

Commit

Permalink
Uses DisposeOnViewTreeLifecycleDestroyed for ComposeView
Browse files Browse the repository at this point in the history
Fixes a problem where claling `dimiss()` / `show()` on `Dialog` windows to re-order them would break `ComposeView` integration.
  • Loading branch information
rjrjr committed Jul 23, 2024
1 parent 040ece4 commit 0c676ae
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,84 @@ internal class ComposeViewTreeIntegrationTest {
.assertIsDisplayed()
}

@Test fun composition_handles_overlay_reordering() {
val composeA: Screen = VanillaComposeRendering(
compatibilityKey = "0",
) {
var counter by rememberSaveable { mutableStateOf(0) }
BasicText(
"Counter: $counter",
Modifier
.clickable { counter++ }
.testTag(CounterTag)
)
}

val composeB: Screen = VanillaComposeRendering(
compatibilityKey = "1",
) {
var counter by rememberSaveable { mutableStateOf(0) }
BasicText(
"Counter2: $counter",
Modifier
.clickable { counter++ }
.testTag(CounterTag2)
)
}

scenario.onActivity {
it.setRendering(
BodyAndOverlaysScreen(
EmptyRendering,
listOf(
TestOverlay(composeA),
TestOverlay(composeB),
// When we move this to the front, both of the other previously-upstream-
// now-downstream dialogs will be dismissed and re-shown.
TestOverlay(EmptyRendering)
)
)
)
}

composeRule.onNodeWithTag(CounterTag)
.assertTextEquals("Counter: 0")
.performClick()
.assertTextEquals("Counter: 1")

composeRule.onNodeWithTag(CounterTag2)
.assertTextEquals("Counter2: 0")
.performClick()
.assertTextEquals("Counter2: 1")

// Reorder the overlays, dialogs will be dismissed and re-shown to preserve order.

scenario.onActivity {
it.setRendering(
BodyAndOverlaysScreen(
EmptyRendering,
listOf(
TestOverlay(EmptyRendering),
TestOverlay(composeB),
TestOverlay(composeA),
)
)
)
}

// Are they still responsive?

composeRule.onNodeWithTag(CounterTag)
.assertTextEquals("Counter: 1")
.performClick()
.assertTextEquals("Counter: 2")

composeRule.onNodeWithTag(CounterTag2)
.assertTextEquals("Counter2: 1")
.performClick()
.assertTextEquals("Counter2: 2")
}

private fun WorkflowUiTestActivity.setBackstack(vararg backstack: Screen) {
setRendering(
BackStackScreen.fromList(listOf<AndroidScreen<*>>(EmptyRendering) + backstack.asList())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.platform.ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.setViewTreeLifecycleOwner
import com.squareup.workflow1.ui.Screen
Expand Down Expand Up @@ -125,6 +126,7 @@ public fun <ScreenT : Screen> ScreenComposableFactory<ScreenT>.asViewFactory():
container: ViewGroup?
): ScreenViewHolder<ScreenT> {
val view = ComposeView(context)
view.setViewCompositionStrategy(DisposeOnViewTreeLifecycleDestroyed)
return ScreenViewHolder(initialEnvironment, view) { newRendering, environment ->

// Update the state whenever a new rendering is emitted.
Expand Down

0 comments on commit 0c676ae

Please sign in to comment.