Skip to content

Commit 2a79fab

Browse files
authored
Merge pull request #705 from square/ray/fml
Fixes rapid BackStackContainer.update calls.
2 parents b264715 + 2f8737b commit 2a79fab

File tree

4 files changed

+109
-4
lines changed

4 files changed

+109
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package com.squareup.sample.container.overviewdetail
2+
3+
import android.content.Context
4+
import android.view.View
5+
import androidx.activity.ComponentActivity
6+
import androidx.test.ext.junit.rules.ActivityScenarioRule
7+
import com.google.common.truth.Truth.assertThat
8+
import com.squareup.workflow1.ui.AndroidViewRendering
9+
import com.squareup.workflow1.ui.BuilderViewFactory
10+
import com.squareup.workflow1.ui.Compatible
11+
import com.squareup.workflow1.ui.Named
12+
import com.squareup.workflow1.ui.ViewEnvironment
13+
import com.squareup.workflow1.ui.ViewFactory
14+
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
15+
import com.squareup.workflow1.ui.backstack.BackStackContainer
16+
import com.squareup.workflow1.ui.backstack.BackStackScreen
17+
import com.squareup.workflow1.ui.bindShowRendering
18+
import com.squareup.workflow1.ui.getRendering
19+
import org.junit.Rule
20+
import org.junit.Test
21+
22+
@OptIn(WorkflowUiExperimentalApi::class)
23+
internal class BackStackContainerTest {
24+
@get:Rule val scenarioRule = ActivityScenarioRule(ComponentActivity::class.java)
25+
private val scenario get() = scenarioRule.scenario
26+
27+
private data class Rendering(val name: String) : Compatible, AndroidViewRendering<Rendering> {
28+
override val compatibilityKey = name
29+
override val viewFactory: ViewFactory<Rendering>
30+
get() = BuilderViewFactory(Rendering::class) { r, e, ctx, _ ->
31+
View(ctx).also { it.bindShowRendering(r, e) { _, _ -> /* Noop */ } }
32+
}
33+
}
34+
35+
@Test fun firstScreenIsRendered() {
36+
scenario.onActivity { activity ->
37+
val c = VisibleBackStackContainer(activity)
38+
39+
c.show(BackStackScreen(Rendering("able")))
40+
val showing = c.visibleRendering as Rendering
41+
assertThat(showing).isEqualTo(Rendering("able"))
42+
}
43+
}
44+
45+
@Test fun secondScreenIsRendered() {
46+
scenario.onActivity { activity ->
47+
val c = VisibleBackStackContainer(activity)
48+
49+
c.show(BackStackScreen(Rendering("able")))
50+
c.show(BackStackScreen(Rendering("baker")))
51+
val showing = c.visibleRendering as Rendering
52+
assertThat(showing).isEqualTo(Rendering("baker"))
53+
}
54+
}
55+
56+
@Test fun thirdScreenIsRendered() {
57+
scenario.onActivity { activity ->
58+
val c = VisibleBackStackContainer(activity)
59+
60+
c.show(BackStackScreen(Rendering("able")))
61+
c.show(BackStackScreen(Rendering("baker")))
62+
c.show(BackStackScreen(Rendering("charlie")))
63+
val showing = c.visibleRendering as Rendering
64+
assertThat(showing).isEqualTo(Rendering("charlie"))
65+
66+
// This used to fail because of our naive use of TransitionManager. The
67+
// transition from baker view to charlie view was dropped because the
68+
// transition from able view to baker view was still in progress.
69+
}
70+
}
71+
72+
@Test fun isDebounced() {
73+
scenario.onActivity { activity ->
74+
val c = VisibleBackStackContainer(activity)
75+
76+
c.show(BackStackScreen(Rendering("able")))
77+
c.show(BackStackScreen(Rendering("able")))
78+
c.show(BackStackScreen(Rendering("able")))
79+
c.show(BackStackScreen(Rendering("able")))
80+
81+
assertThat(c.transitionCount).isEqualTo(1)
82+
}
83+
}
84+
85+
private class VisibleBackStackContainer(context: Context) : BackStackContainer(context) {
86+
var transitionCount = 0
87+
val visibleRendering: Any? get() = getChildAt(0)?.getRendering<Named<*>>()?.wrapped
88+
89+
fun show(rendering: BackStackScreen<*>) {
90+
update(rendering, ViewEnvironment())
91+
}
92+
93+
override fun performTransition(
94+
oldViewMaybe: View?,
95+
newView: View,
96+
popped: Boolean
97+
) {
98+
transitionCount++
99+
super.performTransition(oldViewMaybe, newView, popped)
100+
}
101+
}
102+
}

samples/containers/android/src/androidTest/java/com/squareup/sample/container/overviewdetail/OverviewDetailContainerTest.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,15 @@ import android.view.View
44
import android.widget.FrameLayout
55
import androidx.activity.ComponentActivity
66
import androidx.test.ext.junit.rules.ActivityScenarioRule
7-
import androidx.test.ext.junit.runners.AndroidJUnit4
87
import com.google.common.truth.Truth
98
import com.squareup.sample.container.R
109
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
1110
import com.squareup.workflow1.ui.WorkflowViewStub
1211
import org.junit.Rule
1312
import org.junit.Test
14-
import org.junit.runner.RunWith
1513
import kotlin.test.assertFailsWith
1614

1715
@OptIn(WorkflowUiExperimentalApi::class)
18-
@RunWith(AndroidJUnit4::class)
1916
internal class OverviewDetailContainerTest {
2017
@get:Rule val scenarioRule = ActivityScenarioRule(ComponentActivity::class.java)
2118
private val scenario get() = scenarioRule.scenario
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
1313
import com.squareup.workflow1.ui.backstack.test.fixtures.BackStackContainerLifecycleActivity
1414
import com.squareup.workflow1.ui.backstack.test.fixtures.BackStackContainerLifecycleActivity.TestRendering.LeafRendering
1515
import com.squareup.workflow1.ui.backstack.test.fixtures.BackStackContainerLifecycleActivity.TestRendering.RecurseRendering
16+
import com.squareup.workflow1.ui.backstack.test.fixtures.NoTransitionBackStackContainer
1617
import com.squareup.workflow1.ui.backstack.test.fixtures.ViewStateTestView
1718
import com.squareup.workflow1.ui.backstack.test.fixtures.viewForScreen
1819
import com.squareup.workflow1.ui.backstack.test.fixtures.waitForScreen
@@ -22,8 +23,12 @@ import org.junit.Rule
2223
import org.junit.Test
2324
import org.junit.rules.RuleChain
2425

26+
/**
27+
* Uses a custom subclass, [NoTransitionBackStackContainer], to ensure transitions
28+
* are synchronus.
29+
*/
2530
@OptIn(WorkflowUiExperimentalApi::class)
26-
internal class BackstackContainerTest {
31+
internal class BackStackContainerPersistenceTest {
2732

2833
private val scenarioRule =
2934
ActivityScenarioRule(BackStackContainerLifecycleActivity::class.java)

workflow-ui/container-android/src/main/java/com/squareup/workflow1/ui/backstack/BackStackContainer.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ public open class BackStackContainer @JvmOverloads constructor(
134134
.addTransition(Slide(inEdge).addTarget(newTarget))
135135
.setInterpolator(AccelerateDecelerateInterpolator())
136136

137+
TransitionManager.endTransitions(this)
137138
TransitionManager.go(Scene(this, newView), transition)
138139
return
139140
}

0 commit comments

Comments
 (0)