Skip to content

Introduce ComposeWorkflow. #1357

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

Draft
wants to merge 4 commits into
base: zachklipp/workflownode-poly
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions benchmarks/compose-workflow/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
id("android-defaults")
}

// Note: We are not including our defaults from .buildscript as we do not need the base Workflow
// dependencies that those include.

android {
defaultConfig {
// TODO why isn't this taking?
testInstrumentationRunner = "androidx.benchmark.junit4.AndroidBenchmarkRunner"
}

buildTypes {
debug {
// TODO why isn't this available?
// isDebuggable = false
}
}

namespace = "com.squareup.benchmark.composeworkflow.benchmark"
testNamespace = "$namespace.test"
}

dependencies {
androidTestImplementation(project(":workflow-runtime"))
androidTestImplementation(libs.androidx.benchmark)
androidTestImplementation(libs.androidx.test.espresso.core)
androidTestImplementation(libs.androidx.test.junit)
androidTestImplementation(libs.androidx.test.uiautomator)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-dontobfuscate
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.squareup.benchmark.composeworkflow.benchmark

import androidx.benchmark.junit4.BenchmarkRule
import androidx.benchmark.junit4.measureRepeated
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class ComposeWorkflowMicroBenchmark {

@get:Rule val benchmarkRule = BenchmarkRule()

@Test fun foo() {
benchmarkRule.measureRepeated {
Thread.sleep(100)
}
}
}
3 changes: 3 additions & 0 deletions benchmarks/compose-workflow/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest>
</manifest>
2 changes: 1 addition & 1 deletion benchmarks/dungeon-benchmark/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ android {
}

dependencies {
implementation(libs.androidx.macro.benchmark)
implementation(libs.androidx.benchmark.macro)
implementation(libs.androidx.test.espresso.core)
implementation(libs.androidx.test.junit)
implementation(libs.androidx.test.uiautomator)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ android {
}

dependencies {
implementation(libs.androidx.macro.benchmark)
implementation(libs.androidx.benchmark.macro)
implementation(libs.androidx.test.espresso.core)
implementation(libs.androidx.test.junit)
implementation(libs.androidx.test.uiautomator)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.squareup.benchmarks.performance.complex.poetry.instrumentation

import androidx.compose.runtime.Composable
import androidx.tracing.Trace
import com.squareup.benchmarks.performance.complex.poetry.PerformancePoemWorkflow
import com.squareup.benchmarks.performance.complex.poetry.PerformancePoemsBrowserWorkflow
import com.squareup.benchmarks.performance.complex.poetry.instrumentation.PerformanceTracingInterceptor.Companion.NODES_TO_TRACE
import com.squareup.workflow1.BaseRenderContext
import com.squareup.workflow1.WorkflowExperimentalApi
import com.squareup.workflow1.WorkflowInterceptor
import com.squareup.workflow1.WorkflowInterceptor.RenderContextInterceptor
import com.squareup.workflow1.WorkflowInterceptor.WorkflowSession
Expand All @@ -27,6 +30,24 @@ class PerformanceTracingInterceptor(
context: BaseRenderContext<P, S, O>,
proceed: (P, S, RenderContextInterceptor<P, S, O>?) -> R,
session: WorkflowSession
): R = traceRender(session) {
proceed(renderProps, renderState, null)
}

@OptIn(WorkflowExperimentalApi::class)
@Composable
override fun <P, O, R> onRenderComposeWorkflow(
renderProps: P,
emitOutput: (O) -> Unit,
proceed: @Composable (P, (O) -> Unit) -> R,
session: WorkflowSession
): R = traceRender(session) {
proceed(renderProps, emitOutput)
}

private inline fun <R> traceRender(
session: WorkflowSession,
render: () -> R
): R {
val isRoot = session.parent == null
val traceIdIndex = NODES_TO_TRACE.indexOfFirst { it.second == session.identifier }
Expand All @@ -45,7 +66,7 @@ class PerformanceTracingInterceptor(
Trace.beginSection(sectionName)
}

return proceed(renderProps, renderState, null).also {
return render().also {
if (traceIdIndex > -1 && !sample) {
Trace.endSection()
}
Expand Down
3 changes: 2 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ androidx-lifecycle-viewmodel-core = { module = "androidx.lifecycle:lifecycle-vie
androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle" }
androidx-lifecycle-viewmodel-savedstate = { module = "androidx.lifecycle:lifecycle-viewmodel-savedstate", version.ref = "androidx-lifecycle" }

androidx-macro-benchmark = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "androidx-benchmark" }
androidx-benchmark = { module = "androidx.benchmark:benchmark-junit4", version.ref = "androidx-benchmark" }
androidx-benchmark-macro = { module = "androidx.benchmark:benchmark-macro-junit4", version.ref = "androidx-benchmark" }

androidx-profileinstaller = { module = "androidx.profileinstaller:profileinstaller", version.ref = "androidx-profileinstaller" }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,32 @@ import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.tooling.preview.Preview
import com.squareup.workflow1.Snapshot
import com.squareup.workflow1.StatefulWorkflow
import com.squareup.workflow1.WorkflowExperimentalApi
import com.squareup.workflow1.WorkflowExperimentalRuntime
import com.squareup.workflow1.compose.ComposeWorkflow
import com.squareup.workflow1.config.AndroidRuntimeConfigTools
import com.squareup.workflow1.parse
import com.squareup.workflow1.ui.Screen
import com.squareup.workflow1.ui.compose.ComposeScreen
import com.squareup.workflow1.ui.compose.WorkflowRendering
import com.squareup.workflow1.ui.compose.renderAsState

object InlineRenderingWorkflow : StatefulWorkflow<Unit, Int, Nothing, Screen>() {
@OptIn(WorkflowExperimentalApi::class)
object InlineRenderingWorkflow : ComposeWorkflow<Unit, Nothing, Screen>() {

override fun initialState(
@Composable
override fun produceRendering(
props: Unit,
snapshot: Snapshot?
): Int = snapshot?.bytes?.parse { it.readInt() } ?: 0

override fun render(
renderProps: Unit,
renderState: Int,
context: RenderContext<Unit, Int, Nothing>
): ComposeScreen {
val onClick = context.eventHandler("increment") { state += 1 }
emitOutput: (Nothing) -> Unit
): Screen {
var state by rememberSaveable { mutableIntStateOf(0) }
return ComposeScreen {
Content(renderState, onClick)
Content(state, onClick = { state++ })
}
}

override fun snapshotState(state: Int): Snapshot = Snapshot.of(state)
}

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.compose.ui.graphics.Color
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.squareup.workflow1.SimpleLoggingWorkflowInterceptor
import com.squareup.workflow1.WorkflowExperimentalRuntime
import com.squareup.workflow1.android.renderWorkflowIn
import com.squareup.workflow1.config.AndroidRuntimeConfigTools
Expand Down Expand Up @@ -47,7 +48,8 @@ class NestedRenderingsActivity : AppCompatActivity() {
workflow = RecursiveWorkflow.mapRendering { it.withEnvironment(viewEnvironment) },
scope = viewModelScope,
savedStateHandle = savedState,
runtimeConfig = AndroidRuntimeConfigTools.getAppWorkflowRuntimeConfig()
runtimeConfig = AndroidRuntimeConfigTools.getAppWorkflowRuntimeConfig(),
interceptors = listOf(SimpleLoggingWorkflowInterceptor())
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

package com.squareup.sample.compose.nestedrenderings

import androidx.compose.animation.Animatable
import androidx.compose.animation.core.FastOutLinearInEasing
import androidx.compose.animation.core.LinearOutSlowInEasing
import androidx.compose.animation.core.keyframes
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.layout.Arrangement.SpaceEvenly
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
Expand All @@ -13,12 +21,17 @@ import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.tooling.preview.Preview
import com.squareup.sample.compose.R
Expand All @@ -27,6 +40,7 @@ import com.squareup.workflow1.ui.Screen
import com.squareup.workflow1.ui.compose.ScreenComposableFactory
import com.squareup.workflow1.ui.compose.WorkflowRendering
import com.squareup.workflow1.ui.compose.tooling.Preview
import kotlin.time.DurationUnit.MILLISECONDS

/**
* Composition local of [Color] to use as the background color for a [RecursiveComposableFactory].
Expand All @@ -44,7 +58,26 @@ val RecursiveComposableFactory = ScreenComposableFactory<Rendering> { rendering
.compositeOver(Color.Black)
}

Card(backgroundColor = color) {
var lastFlashedTrigger by remember { mutableIntStateOf(rendering.flashTrigger) }
val flashAlpha = remember { Animatable(Color(0x00FFFFFF)) }

// Flash the card white when asked.
LaunchedEffect(rendering.flashTrigger) {
if (rendering.flashTrigger != 0) {
lastFlashedTrigger = rendering.flashTrigger
flashAlpha.animateTo(Color(0x00FFFFFF), animationSpec = keyframes {
Color.White at (rendering.flashTime / 7).toInt(MILLISECONDS) using FastOutLinearInEasing
Color(0x00FFFFFF) at rendering.flashTime.toInt(MILLISECONDS) using LinearOutSlowInEasing
})
}
}

Card(
backgroundColor = flashAlpha.value.compositeOver(color),
modifier = Modifier.pointerInput(rendering) {
detectTapGestures(onPress = { rendering.onSelfClicked() })
}
) {
Column(
Modifier
.padding(dimensionResource(R.dimen.recursive_padding))
Expand Down Expand Up @@ -76,10 +109,14 @@ fun RecursiveViewFactoryPreview() {
StringRendering("foo"),
Rendering(
children = listOf(StringRendering("bar")),
flashTrigger = 0,
onSelfClicked = {},
onAddChildClicked = {},
onResetClicked = {}
)
),
flashTrigger = 0,
onSelfClicked = {},
onAddChildClicked = {},
onResetClicked = {}
),
Expand Down
Loading
Loading