Skip to content

Commit 4704be0

Browse files
committed
Common flow child flow demo
Refs: #11
1 parent 62a875e commit 4704be0

32 files changed

Lines changed: 758 additions & 9 deletions

.github/workflows/check.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
- name: Grant execute permission for gradlew
3434
run: chmod +x gradlew
3535
- name: Check with gradle
36-
run: ./gradlew runUnitTests :examples:lce:assembleDebug :examples:welcome:welcome:assembleDebug :examples:multi:navbar:assembleDebug :examples:multi:parallel:assembleDebug :examples:lifecycle:assembleDebug :examples:di:app:assembleDebug :examples:commonflow:assembleDebug --no-daemon --no-configuration-cache
36+
run: ./gradlew runUnitTests :examples:lce:assembleDebug :examples:welcome:welcome:assembleDebug :examples:multi:navbar:assembleDebug :examples:multi:parallel:assembleDebug :examples:lifecycle:assembleDebug :examples:di:app:assembleDebug :examples:book:app:assembleDebug :examples:book:book:demo:assembleDebug --no-daemon --no-configuration-cache
3737
- name: Upload problems report
3838
uses: actions/upload-artifact@v4
3939
if: failure()

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ tasks.register("runDiExampleUnitTests") {
129129
}
130130

131131
tasks.register("runBooksExampleUnitTests") {
132-
dependsOn(":examples:books:item:testDebugUnitTest")
132+
dependsOn(":examples:books:book:testDebugUnitTest")
133133
dependsOn(":examples:books:app:testDebugUnitTest")
134134
description = "Run unit tests for books app."
135135
}

examples/books/app/src/test/kotlin/com/motorro/statemachine/books/app/state/ItemListStateTest.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ internal class ItemListStateTest : BaseStateTest() {
5353
state.start(stateMachine)
5454

5555
coVerify(ordering = Ordering.ORDERED) {
56-
stateMachine.setUiState(MainUiState.Loading)
57-
stateMachine.setUiState(MainUiState.Master(persistentListOf(BOOK_1)))
56+
stateMachine.setUiState(MainUiState.List.Loading)
57+
stateMachine.setUiState(MainUiState.List.Master(persistentListOf(BOOK_1)))
5858
}
5959
}
6060

@@ -65,8 +65,8 @@ internal class ItemListStateTest : BaseStateTest() {
6565
state.start(stateMachine)
6666

6767
coVerify(ordering = Ordering.ORDERED) {
68-
stateMachine.setUiState(MainUiState.Master(persistentListOf(BOOK_2)))
69-
stateMachine.setUiState(MainUiState.Master(persistentListOf(BOOK_1)))
68+
stateMachine.setUiState(MainUiState.List.Master(persistentListOf(BOOK_2)))
69+
stateMachine.setUiState(MainUiState.List.Master(persistentListOf(BOOK_1)))
7070
}
7171
}
7272

@@ -78,9 +78,9 @@ internal class ItemListStateTest : BaseStateTest() {
7878
items.emit(persistentListOf(BOOK_2))
7979

8080
coVerify(ordering = Ordering.ORDERED) {
81-
stateMachine.setUiState(MainUiState.Loading)
82-
stateMachine.setUiState(MainUiState.Master(persistentListOf(BOOK_1)))
83-
stateMachine.setUiState(MainUiState.Master(persistentListOf(BOOK_2)))
81+
stateMachine.setUiState(MainUiState.List.Loading)
82+
stateMachine.setUiState(MainUiState.List.Master(persistentListOf(BOOK_1)))
83+
stateMachine.setUiState(MainUiState.List.Master(persistentListOf(BOOK_2)))
8484
}
8585
}
8686

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright 2026 Nikolai Kotchetkov.
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
14+
@file:Suppress("unused")
15+
16+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
17+
18+
/*
19+
* Copyright 2022 Nikolai Kotchetkov.
20+
* Licensed under the Apache License, Version 2.0 (the "License");
21+
* you may not use this file except in compliance with the License.
22+
* You may obtain a copy of the License at
23+
* http://www.apache.org/licenses/LICENSE-2.0
24+
* Unless required by applicable law or agreed to in writing, software
25+
* distributed under the License is distributed on an "AS IS" BASIS,
26+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27+
* See the License for the specific language governing permissions and
28+
* limitations under the License.
29+
*/
30+
31+
plugins {
32+
id("com.android.application")
33+
id("org.jetbrains.kotlin.plugin.compose")
34+
alias(libs.plugins.google.ksp)
35+
alias(libs.plugins.hilt)
36+
}
37+
38+
val versionCode: String by project.extra
39+
val versionName: String by project.extra
40+
val androidMinSdkVersion: Int by project.extra
41+
val androidCompileSdkVersion: Int by project.extra
42+
val androidTargetSdkVersion: Int by project.extra
43+
44+
android {
45+
compileSdk = androidCompileSdkVersion
46+
47+
defaultConfig {
48+
applicationId = "com.motorro.statemachine.books.book.demo"
49+
50+
minSdk = androidMinSdkVersion
51+
targetSdk = androidTargetSdkVersion
52+
versionCode = versionCode
53+
versionName = versionName
54+
55+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
56+
vectorDrawables {
57+
useSupportLibrary = true
58+
}
59+
}
60+
61+
buildTypes {
62+
release {
63+
isMinifyEnabled = false
64+
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
65+
}
66+
}
67+
compileOptions {
68+
isCoreLibraryDesugaringEnabled = true
69+
sourceCompatibility = JavaVersion.VERSION_17
70+
targetCompatibility = JavaVersion.VERSION_17
71+
}
72+
kotlin {
73+
compilerOptions {
74+
jvmTarget.set(JvmTarget.JVM_17)
75+
}
76+
}
77+
buildFeatures {
78+
compose = true
79+
}
80+
packaging {
81+
resources {
82+
excludes += "/META-INF/{AL2.0,LGPL2.1}"
83+
}
84+
}
85+
namespace = "com.motorro.statemachine.books.book.demo"
86+
}
87+
88+
dependencies {
89+
implementation(project(":commonstatemachine"))
90+
implementation(project(":commonflow:data"))
91+
implementation(project(":commonflow:compose"))
92+
implementation(project(":commonflow:viewmodel"))
93+
94+
implementation(project(":examples:commoncore"))
95+
implementation(project(":examples:androidcore"))
96+
implementation(project(":examples:books:domain"))
97+
implementation(project(":examples:books:book"))
98+
99+
coreLibraryDesugaring(libs.desugaring)
100+
101+
implementation(libs.androidx.core)
102+
implementation(libs.androidx.lifecycle.runtime)
103+
implementation(libs.androidx.lifecycle.livedata)
104+
implementation(libs.androidx.lifecycle.viewmodel)
105+
106+
implementation(libs.kotlin.immutable)
107+
implementation(libs.kotlin.coroutines.core)
108+
implementation(libs.kotlin.coroutines.android)
109+
110+
implementation(platform(libs.compose.bom))
111+
112+
implementation(libs.bundles.compose.core)
113+
implementation(libs.compose.activity)
114+
implementation(libs.compose.viewmodel)
115+
implementation(libs.compose.foundation)
116+
implementation(libs.compose.foundation.layouts)
117+
implementation(libs.compose.material.icons)
118+
119+
implementation(libs.hilt.android)
120+
implementation(libs.hilt.compose)
121+
ksp(libs.hilt.compiler)
122+
ksp(libs.hilt.compiler.androidx)
123+
124+
debugImplementation(libs.compose.tooling)
125+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
~ Copyright 2022 Nikolai Kotchetkov.
4+
~ Licensed under the Apache License, Version 2.0 (the "License");
5+
~ you may not use this file except in compliance with the License.
6+
~ You may obtain a copy of the License at
7+
~ http://www.apache.org/licenses/LICENSE-2.0
8+
~ Unless required by applicable law or agreed to in writing, software
9+
~ distributed under the License is distributed on an "AS IS" BASIS,
10+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
~ See the License for the specific language governing permissions and
12+
~ limitations under the License.
13+
-->
14+
15+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
16+
<application
17+
android:allowBackup="true"
18+
android:name=".App"
19+
android:icon="@mipmap/ic_launcher"
20+
android:label="@string/app_name"
21+
android:roundIcon="@mipmap/ic_launcher_round"
22+
android:supportsRtl="true"
23+
android:theme="@style/Theme.Book">
24+
<activity
25+
android:name=".MainActivity"
26+
android:exported="true"
27+
android:theme="@style/Theme.Book">
28+
<intent-filter>
29+
<action android:name="android.intent.action.MAIN" />
30+
<category android:name="android.intent.category.LAUNCHER" />
31+
</intent-filter>
32+
</activity>
33+
</application>
34+
35+
</manifest>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2026 Nikolai Kotchetkov.
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
14+
package com.motorro.statemachine.books.book.demo
15+
16+
import android.app.Application
17+
import dagger.hilt.android.HiltAndroidApp
18+
import timber.log.Timber
19+
20+
@HiltAndroidApp
21+
class App : Application() {
22+
override fun onCreate() {
23+
super.onCreate()
24+
setupLogger()
25+
}
26+
27+
private fun setupLogger() {
28+
Timber.plant(Timber.DebugTree())
29+
}
30+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2026 Nikolai Kotchetkov.
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
14+
package com.motorro.statemachine.books.book.demo
15+
16+
import android.os.Bundle
17+
import androidx.activity.ComponentActivity
18+
import androidx.activity.enableEdgeToEdge
19+
import com.motorro.commonstatemachine.flow.viewmodel.setStateMachineContent
20+
import com.motorro.statemachine.androidcore.ui.theme.CommonStateMachineTheme
21+
import com.motorro.statemachine.books.book.api.BookGesture
22+
import com.motorro.statemachine.books.book.api.BookInput
23+
import com.motorro.statemachine.books.book.api.BookUiState
24+
import com.motorro.statemachine.books.book.ui.BookScreen
25+
import dagger.hilt.android.AndroidEntryPoint
26+
import dagger.hilt.android.lifecycle.withCreationCallback
27+
28+
@AndroidEntryPoint
29+
class MainActivity : ComponentActivity() {
30+
override fun onCreate(savedInstanceState: Bundle?) {
31+
enableEdgeToEdge()
32+
super.onCreate(savedInstanceState)
33+
34+
setStateMachineContent<BookGesture, BookUiState, Unit, MainViewModel>(
35+
extrasProducer = {
36+
defaultViewModelCreationExtras.withCreationCallback<MainViewModel.Factory> {
37+
it.create(BookInput(BOOK.id, BOOK.title))
38+
}
39+
},
40+
content = { state, onGesture ->
41+
CommonStateMachineTheme {
42+
BookScreen(state, onGesture)
43+
}
44+
}
45+
)
46+
}
47+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2026 Nikolai Kotchetkov.
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
14+
package com.motorro.statemachine.books.book.demo
15+
16+
import com.motorro.commonstatemachine.flow.viewmodel.CommonFlowViewModel
17+
import com.motorro.statemachine.books.book.api.BookApi
18+
import com.motorro.statemachine.books.book.api.BookGesture
19+
import com.motorro.statemachine.books.book.api.BookInput
20+
import com.motorro.statemachine.books.book.api.BookUiState
21+
import dagger.assisted.Assisted
22+
import dagger.assisted.AssistedFactory
23+
import dagger.assisted.AssistedInject
24+
import dagger.hilt.android.lifecycle.HiltViewModel
25+
26+
@HiltViewModel(assistedFactory = MainViewModel.Factory::class)
27+
class MainViewModel @AssistedInject internal constructor(
28+
@Assisted input: BookInput,
29+
bookApi: BookApi
30+
) : CommonFlowViewModel<BookGesture, BookUiState, BookInput, Unit>(
31+
api = bookApi,
32+
init = input
33+
) {
34+
@AssistedFactory
35+
interface Factory {
36+
fun create(input: BookInput): MainViewModel
37+
}
38+
}

0 commit comments

Comments
 (0)