Skip to content

Commit 2fff3a7

Browse files
Introduce ComposeWorkflow.
This is part of go/compose-based-workflows.
1 parent fbc9cf7 commit 2fff3a7

File tree

23 files changed

+763
-21
lines changed

23 files changed

+763
-21
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
plugins {
2+
id("com.android.application")
3+
id("kotlin-android")
4+
id("android-sample-app")
5+
id("android-ui-tests")
6+
alias(libs.plugins.compose.compiler)
7+
}
8+
9+
android {
10+
defaultConfig {
11+
applicationId = "com.squareup.sample.hellocomposeworkflow"
12+
}
13+
namespace = "com.squareup.sample.hellocomposeworkflow"
14+
}
15+
16+
dependencies {
17+
debugImplementation(libs.squareup.leakcanary.android)
18+
19+
implementation(libs.androidx.activity.ktx)
20+
implementation(libs.androidx.lifecycle.viewmodel.ktx)
21+
implementation(libs.androidx.lifecycle.viewmodel.savedstate)
22+
implementation(libs.androidx.viewbinding)
23+
24+
implementation(project(":workflow-ui:core-android"))
25+
implementation(project(":workflow-ui:core-common"))
26+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<issues format="6" by="lint 7.4.1" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.1)" variant="all" version="7.4.1">
3+
4+
<issue
5+
id="DataExtractionRules"
6+
message="The attribute `android:allowBackup` is deprecated from Android 12 and higher and may be removed in future versions. Consider adding the attribute `android:dataExtractionRules` specifying an `@xml` resource which configures cloud backups and device transfers on Android 12 and higher."
7+
errorLine1=" android:allowBackup=&quot;false&quot;"
8+
errorLine2=" ~~~~~">
9+
<location
10+
file="src/main/AndroidManifest.xml"
11+
line="6"
12+
column="28"/>
13+
</issue>
14+
15+
</issues>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.squareup.sample.hellocomposeworkflow
2+
3+
import androidx.test.espresso.Espresso.onView
4+
import androidx.test.espresso.action.ViewActions.click
5+
import androidx.test.espresso.assertion.ViewAssertions.matches
6+
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
7+
import androidx.test.espresso.matcher.ViewMatchers.withText
8+
import androidx.test.ext.junit.rules.ActivityScenarioRule
9+
import androidx.test.ext.junit.runners.AndroidJUnit4
10+
import com.squareup.workflow1.ui.internal.test.IdlingDispatcherRule
11+
import leakcanary.DetectLeaksAfterTestSuccess
12+
import org.junit.Rule
13+
import org.junit.Test
14+
import org.junit.rules.RuleChain
15+
import org.junit.runner.RunWith
16+
17+
@RunWith(AndroidJUnit4::class)
18+
class HelloComposeWorkflowAppTest {
19+
20+
private val scenarioRule = ActivityScenarioRule(HelloComposeWorkflowActivity::class.java)
21+
22+
@get:Rule val rules: RuleChain = RuleChain.outerRule(DetectLeaksAfterTestSuccess())
23+
.around(scenarioRule)
24+
.around(IdlingDispatcherRule)
25+
26+
@Test fun togglesHelloAndGoodbye() {
27+
onView(withText("Hello"))
28+
.check(matches(isDisplayed()))
29+
.perform(click())
30+
31+
onView(withText("Goodbye"))
32+
.check(matches(isDisplayed()))
33+
.perform(click())
34+
35+
onView(withText("Hello"))
36+
.check(matches(isDisplayed()))
37+
}
38+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools">
4+
5+
<application
6+
android:allowBackup="false"
7+
android:label="@string/app_name"
8+
android:theme="@style/AppTheme"
9+
tools:ignore="GoogleAppIndexingWarning,MissingApplicationIcon"
10+
>
11+
12+
<activity android:name="com.squareup.sample.hellocomposeworkflow.HelloComposeWorkflowActivity"
13+
android:exported="true">
14+
15+
<intent-filter>
16+
<action android:name="android.intent.action.MAIN" />
17+
<category android:name="android.intent.category.LAUNCHER" />
18+
</intent-filter>
19+
20+
</activity>
21+
22+
</application>
23+
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.squareup.sample.hellocomposeworkflow
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.runtime.getValue
5+
import androidx.compose.runtime.mutableStateOf
6+
import androidx.compose.runtime.remember
7+
import androidx.compose.runtime.setValue
8+
import com.squareup.sample.hellocomposeworkflow.HelloComposeWorkflow.State.Goodbye
9+
import com.squareup.sample.hellocomposeworkflow.HelloComposeWorkflow.State.Hello
10+
import com.squareup.workflow1.WorkflowExperimentalApi
11+
import com.squareup.workflow1.compose.ComposeWorkflow
12+
13+
@OptIn(WorkflowExperimentalApi::class)
14+
object HelloComposeWorkflow : ComposeWorkflow<Unit, Nothing, HelloRendering>() {
15+
enum class State {
16+
Hello,
17+
Goodbye
18+
}
19+
20+
@Composable
21+
override fun produceRendering(
22+
props: Unit,
23+
emitOutput: (Nothing) -> Unit
24+
): HelloRendering {
25+
var state by remember { mutableStateOf(Hello) }
26+
println("OMG recomposing state=$state")
27+
return HelloRendering(
28+
message = state.name,
29+
onClick = {
30+
println("OMG onClick! state=$state")
31+
state = when (state) {
32+
Hello -> Goodbye
33+
Goodbye -> Hello
34+
}
35+
}
36+
)
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
@file:OptIn(WorkflowExperimentalRuntime::class)
2+
3+
package com.squareup.sample.hellocomposeworkflow
4+
5+
import android.os.Bundle
6+
import androidx.activity.viewModels
7+
import androidx.appcompat.app.AppCompatActivity
8+
import androidx.lifecycle.SavedStateHandle
9+
import androidx.lifecycle.ViewModel
10+
import androidx.lifecycle.viewModelScope
11+
import com.squareup.workflow1.WorkflowExperimentalRuntime
12+
import com.squareup.workflow1.config.AndroidRuntimeConfigTools
13+
import com.squareup.workflow1.ui.renderWorkflowIn
14+
import com.squareup.workflow1.ui.workflowContentView
15+
import kotlinx.coroutines.flow.StateFlow
16+
17+
class HelloComposeWorkflowActivity : AppCompatActivity() {
18+
override fun onCreate(savedInstanceState: Bundle?) {
19+
super.onCreate(savedInstanceState)
20+
21+
// This ViewModel will survive configuration changes. It's instantiated
22+
// by the first call to viewModels(), and that original instance is returned by
23+
// succeeding calls.
24+
val model: HelloViewModel by viewModels()
25+
workflowContentView.take(lifecycle, model.renderings)
26+
}
27+
}
28+
29+
class HelloViewModel(savedState: SavedStateHandle) : ViewModel() {
30+
val renderings: StateFlow<HelloRendering> by lazy {
31+
renderWorkflowIn(
32+
workflow = HelloComposeWorkflow,
33+
scope = viewModelScope,
34+
savedStateHandle = savedState,
35+
runtimeConfig = AndroidRuntimeConfigTools.getAppWorkflowRuntimeConfig()
36+
)
37+
}
38+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.squareup.sample.hellocomposeworkflow
2+
3+
import com.squareup.sample.hellocomposeworkflow.databinding.HelloGoodbyeLayoutBinding
4+
import com.squareup.workflow1.ui.AndroidScreen
5+
import com.squareup.workflow1.ui.ScreenViewFactory
6+
import com.squareup.workflow1.ui.ScreenViewFactory.Companion.fromViewBinding
7+
8+
data class HelloRendering(
9+
val message: String,
10+
val onClick: () -> Unit
11+
) : AndroidScreen<HelloRendering> {
12+
override val viewFactory: ScreenViewFactory<HelloRendering> =
13+
fromViewBinding(HelloGoodbyeLayoutBinding::inflate) { r, _ ->
14+
helloMessage.text = r.message
15+
helloMessage.setOnClickListener { r.onClick() }
16+
}
17+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:orientation="vertical"
4+
android:layout_width="match_parent"
5+
android:layout_height="match_parent">
6+
7+
<TextView
8+
android:id="@+id/hello_message"
9+
android:layout_width="match_parent"
10+
android:layout_height="match_parent"
11+
android:gravity="center"
12+
/>
13+
14+
</LinearLayout>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<resources>
2+
<string name="app_name">Hello Compose Workflow</string>
3+
</resources>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<resources>
2+
3+
<!-- Base application theme. -->
4+
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
5+
<!-- Customize your theme here. -->
6+
</style>
7+
8+
</resources>

0 commit comments

Comments
 (0)