Skip to content

Commit

Permalink
Friendlier construction API for BackStackScreen
Browse files Browse the repository at this point in the history
* Deprecates the confusing `bottom: T, rest: List` constructor
* Adds `fromList` and `fromListOrNull` factory functions to `BackStackScreen.Companion`, since no one ever finds the `List` extensions
  • Loading branch information
rjrjr committed Sep 21, 2023
1 parent 10e9c88 commit 5d385ce
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,9 @@ internal class ComposeViewTreeIntegrationTest {
}

private fun WorkflowUiTestActivity.setBackstack(vararg backstack: TestComposeRendering) {
setRendering(BackStackScreen(EmptyRendering, backstack.asList()))
setRendering(
BackStackScreen.fromList(listOf<AndroidScreen<*>>(EmptyRendering) + backstack.asList())
)
}

data class TestOverlay(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ internal class BackStackContainerLifecycleActivity : AbstractLifecycleTestActivi
setRendering(backstack.asList().toBackstackWithBase())

private fun List<TestRendering>.toBackstackWithBase() =
BackStackScreen(BaseRendering, this)
BackStackScreen.fromList(listOf<Screen>(BaseRendering) + this)
}

internal fun ActivityScenario<BackStackContainerLifecycleActivity>.viewForScreen(
Expand Down
7 changes: 7 additions & 0 deletions workflow-ui/core-common/api/core-common.api
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,10 @@ public final class com/squareup/workflow1/ui/container/BackStackConfigKt {
}

public final class com/squareup/workflow1/ui/container/BackStackScreen : com/squareup/workflow1/ui/Container, com/squareup/workflow1/ui/Screen {
public static final field Companion Lcom/squareup/workflow1/ui/container/BackStackScreen$Companion;
public fun <init> (Lcom/squareup/workflow1/ui/Screen;Ljava/util/List;)V
public fun <init> (Lcom/squareup/workflow1/ui/Screen;[Lcom/squareup/workflow1/ui/Screen;)V
public synthetic fun <init> (Ljava/util/List;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun asSequence ()Lkotlin/sequences/Sequence;
public fun equals (Ljava/lang/Object;)Z
public final fun get (I)Lcom/squareup/workflow1/ui/Screen;
Expand All @@ -229,6 +231,11 @@ public final class com/squareup/workflow1/ui/container/BackStackScreen : com/squ
public fun toString ()Ljava/lang/String;
}

public final class com/squareup/workflow1/ui/container/BackStackScreen$Companion {
public final fun fromList (Ljava/util/List;)Lcom/squareup/workflow1/ui/container/BackStackScreen;
public final fun fromListOrNull (Ljava/util/List;)Lcom/squareup/workflow1/ui/container/BackStackScreen;
}

public final class com/squareup/workflow1/ui/container/BackStackScreenKt {
public static final fun toBackStackScreen (Ljava/util/List;)Lcom/squareup/workflow1/ui/container/BackStackScreen;
public static final fun toBackStackScreenOrNull (Ljava/util/List;)Lcom/squareup/workflow1/ui/container/BackStackScreen;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package com.squareup.workflow1.ui.container
import com.squareup.workflow1.ui.Container
import com.squareup.workflow1.ui.Screen
import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
import com.squareup.workflow1.ui.container.BackStackScreen.Companion
import com.squareup.workflow1.ui.container.BackStackScreen.Companion.fromList
import com.squareup.workflow1.ui.container.BackStackScreen.Companion.fromListOrNull

/**
* Represents an active screen ([top]), and a set of previously visited screens to which we may
Expand All @@ -13,25 +16,31 @@ import com.squareup.workflow1.ui.WorkflowUiExperimentalApi
*
* UI kits are expected to provide handling for this class by default.
*
* @param bottom the bottom-most entry in the stack
* @param rest the rest of the stack, empty by default
* @see fromList
* @see fromListOrNull
*/
@WorkflowUiExperimentalApi
public class BackStackScreen<StackedT : Screen>(
bottom: StackedT,
rest: List<StackedT>
public class BackStackScreen<StackedT : Screen> private constructor(
public val frames: List<StackedT>
) : Screen, Container<Screen, StackedT> {
/**
* Creates a screen with elements listed from the [bottom] to the top.
*/
public constructor(
bottom: StackedT,
vararg rest: StackedT
) : this(bottom, rest.toList())
) : this(listOf(bottom) + rest)

override fun asSequence(): Sequence<StackedT> = frames.asSequence()
@Deprecated(
"Use fromList",
ReplaceWith("BackStackScreen.fromList(listOf(bottom) + rest)")
)
public constructor(
bottom: StackedT,
rest: List<StackedT>
) : this(listOf(bottom) + rest)

public val frames: List<StackedT> = listOf(bottom) + rest
override fun asSequence(): Sequence<StackedT> = frames.asSequence()

/**
* The active screen.
Expand All @@ -49,7 +58,7 @@ public class BackStackScreen<StackedT : Screen>(
return if (other == null) {
this
} else {
BackStackScreen(frames[0], frames.subList(1, frames.size) + other.frames)
BackStackScreen(frames + other.frames)
}
}

Expand All @@ -75,16 +84,37 @@ public class BackStackScreen<StackedT : Screen>(
override fun toString(): String {
return "${this::class.java.simpleName}($frames)"
}

public companion object {
/**
* Builds a [BackStackScreen] from a non-empty list of [frames].
*
* @throws IllegalArgumentException is [frames] is empty
*/
public fun <T : Screen> fromList(frames: List<T>): BackStackScreen<T> {
require(frames.isNotEmpty()) {
"A BackStackScreen must have at least one frame."
}
return BackStackScreen(frames)
}

/**
* Builds a [BackStackScreen] from a list of [frames], or returns `null`
* if [frames] is empty.
*/
public fun <T : Screen> fromListOrNull(frames: List<T>): BackStackScreen<T>? {
return when {
frames.isEmpty() -> null
else -> BackStackScreen(frames)
}
}
}
}

@WorkflowUiExperimentalApi
public fun <T : Screen> List<T>.toBackStackScreenOrNull(): BackStackScreen<T>? = when {
isEmpty() -> null
else -> toBackStackScreen()
}
public fun <T : Screen> List<T>.toBackStackScreenOrNull(): BackStackScreen<T>? =
fromListOrNull(this)

@WorkflowUiExperimentalApi
public fun <T : Screen> List<T>.toBackStackScreen(): BackStackScreen<T> {
require(isNotEmpty())
return BackStackScreen(first(), subList(1, size))
}
public fun <T : Screen> List<T>.toBackStackScreen(): BackStackScreen<T> =
Companion.fromList(this)
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,8 @@ internal class BackStackScreenTest {

@Test fun `bottom and rest`() {
assertThat(
BackStackScreen(
bottom = S(1),
rest = listOf(S(2), S(3), S(4))
BackStackScreen.fromList(
listOf(element = S(1)) + listOf(S(2), S(3), S(4))
)
).isEqualTo(BackStackScreen(S(1), S(2), S(3), S(4)))
}
Expand Down

0 comments on commit 5d385ce

Please sign in to comment.