-
Notifications
You must be signed in to change notification settings - Fork 101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduces fun Screen.deepMap(Screen): Screen
#1092
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
@file:OptIn(WorkflowUiExperimentalApi::class) | ||
|
||
package com.squareup.workflow1.ui | ||
|
||
import com.google.common.truth.Truth.assertThat | ||
import com.squareup.workflow1.ui.container.BackStackScreen | ||
import com.squareup.workflow1.ui.container.EnvironmentScreen | ||
import com.squareup.workflow1.ui.container.withEnvironment | ||
import org.junit.Test | ||
|
||
internal class ScreenContainerTest { | ||
object MyScreen : Screen | ||
|
||
@Test | ||
fun deepMapRecurses() { | ||
val backStack = BackStackScreen(NamedScreen(MyScreen, "name")) | ||
|
||
@Suppress("UNCHECKED_CAST") | ||
val mappedBackStack = backStack | ||
.deepMap { it.withEnvironment() } as BackStackScreen<NamedScreen<EnvironmentScreen<MyScreen>>> | ||
|
||
assertThat(mappedBackStack.top.content.content).isSameInstanceAs(MyScreen) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.squareup.workflow1.ui | ||
|
||
@WorkflowUiExperimentalApi | ||
public fun interface VisualFactory<ContextT, in RenderingT, VisualT> { | ||
/** | ||
* Given a ui model ([rendering]), creates a [VisualHolder] which pairs: | ||
* | ||
* - a native view system object of type [VisualT] -- a [visual][VisualHolder.visual] | ||
* - an [update function][VisualHolder.update] to apply [RenderingT] instances to | ||
* the new [VisualT] instance. | ||
* | ||
* This method must not call [VisualHolder.update], to ensure that callers have | ||
* complete control over the lifecycle of the new [VisualT]. | ||
* | ||
* @param getFactory can be used to make recursive calls to build VisualT | ||
* instances for sub-parts of [rendering] | ||
*/ | ||
public fun createOrNull( | ||
rendering: RenderingT, | ||
context: ContextT, | ||
environment: ViewEnvironment, | ||
getFactory: (ViewEnvironment) -> VisualFactory<ContextT, Any, VisualT> | ||
): VisualHolder<RenderingT, VisualT>? | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.squareup.workflow1.ui | ||
|
||
@WorkflowUiExperimentalApi | ||
public interface VisualHolder<in RenderingT, out VisualT> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems like some of the kdoc for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Uh oh. I think this and |
||
public val visual: VisualT | ||
|
||
public fun update(rendering: RenderingT): Boolean | ||
|
||
public companion object { | ||
public operator fun <RenderingT, VisualT> invoke( | ||
visual: VisualT, | ||
onUpdate: (RenderingT) -> Unit | ||
): VisualHolder<RenderingT, VisualT> { | ||
return object : VisualHolder<RenderingT, VisualT> { | ||
override val visual = visual | ||
|
||
override fun update(rendering: RenderingT): Boolean { | ||
onUpdate(rendering) | ||
return true | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package com.squareup.workflow1.ui | ||
|
||
@WorkflowUiExperimentalApi | ||
public interface ScreenContainer<out C : Screen> : Container<Screen, C>, Screen { | ||
public override fun <D : Screen> map(transform: (C) -> D): ScreenContainer<D> | ||
} | ||
|
||
@WorkflowUiExperimentalApi | ||
public interface ScreenWrapper<out C : Screen> : ScreenContainer<C>, Wrapper<Screen, C>, Screen { | ||
public override fun <D : Screen> map(transform: (C) -> D): ScreenWrapper<D> | ||
} | ||
|
||
/** | ||
* Applies [transform] to the receiver unless it is a [ScreenContainer]. In that case, | ||
* makes a recursive call to [ScreenContainer.map] and applies [deepMap] to its | ||
* contents. | ||
* | ||
* For example, consider this snippet: | ||
* | ||
* val backStack = BackStackScreen(SomeWrapper(theRealScreen)) | ||
* val loggingBackStack = backStack.deepMap { WithLogging(it) } | ||
* | ||
* `loggingBackStack` will have a structure like so: | ||
* | ||
* BackStackScreen(SomeWrapper(WithLogging(theRealScreen))) | ||
*/ | ||
@WorkflowUiExperimentalApi | ||
public fun Screen.deepMap(transform: (Screen) -> Screen): Screen { | ||
return if (this is ScreenContainer<*>) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You know what? I don't know that
|
||
map { it.deepMap(transform) } | ||
} else { | ||
transform(this) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.