Skip to content

Commit 12d1112

Browse files
authored
Content transition api & predictive back example (#125)
Implements seekable transition + animated content Implements transition api (controllable navigate & back transitions) Predictive back example Shared element transition example Predictive back iOS example implements -> #27 Fix android bug with removeLast -> #127 Add nav listener -> #132
1 parent 8241587 commit 12d1112

File tree

33 files changed

+1091
-132
lines changed

33 files changed

+1091
-132
lines changed

.editorconfig

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,18 @@ insert_final_newline = false
77
max_line_length = 120
88
tab_width = 4
99

10-
[*.yml]
11-
indent_size = 2
10+
[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.jspx,*.pom,*.rng,*.tagx,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}]
11+
ij_xml_align_attributes = true
12+
ij_xml_align_text = false
13+
ij_xml_attribute_wrap = normal
14+
ij_xml_keep_line_breaks = true
15+
ij_xml_keep_line_breaks_in_text = true
16+
ij_xml_space_after_tag_name = false
17+
ij_xml_space_around_equals_in_attribute = false
18+
ij_xml_space_inside_empty_tag = false
19+
ij_xml_text_wrap = normal
1220

1321
[{*.kt,*.kts}]
14-
ij_kotlin_line_break_after_multiline_when_entry = false
1522
ij_kotlin_name_count_to_use_star_import = 5
16-
ij_kotlin_name_count_to_use_star_import_for_members = 3
23+
ij_kotlin_name_count_to_use_star_import_for_members = 3
24+
ij_kotlin_line_break_after_multiline_when_entry = false

example/app/composeApp/src/androidMain/AndroidManifest.xml

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,36 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
33

4-
<uses-feature android:name="android.hardware.camera" />
5-
<uses-permission android:name="android.permission.CAMERA" />
4+
<uses-feature android:name="android.hardware.camera"/>
5+
<uses-permission android:name="android.permission.CAMERA"/>
66

77
<application
88
android:allowBackup="true"
99
android:label="@string/app_name"
1010
android:supportsRtl="true"
1111
android:name=".MainApplication"
12-
android:theme="@android:style/Theme.Material.Light.NoActionBar">
12+
android:enableOnBackInvokedCallback="true"
13+
android:theme="@android:style/Theme.Material.Light.NoActionBar">
1314
<activity
1415
android:name=".MainActivity"
1516
android:exported="true"
1617
android:launchMode="singleInstance"
1718
android:configChanges="screenSize|screenLayout|orientation">
1819

1920
<intent-filter>
20-
<action android:name="android.intent.action.MAIN" />
21-
<category android:name="android.intent.category.LAUNCHER" />
21+
<action android:name="android.intent.action.MAIN"/>
22+
<category android:name="android.intent.category.LAUNCHER"/>
2223
</intent-filter>
2324

2425
<intent-filter android:autoVerify="false">
25-
<action android:name="android.intent.action.VIEW" />
26+
<action android:name="android.intent.action.VIEW"/>
2627

27-
<category android:name="android.intent.category.DEFAULT" />
28-
<category android:name="android.intent.category.BROWSABLE" />
28+
<category android:name="android.intent.category.DEFAULT"/>
29+
<category android:name="android.intent.category.BROWSABLE"/>
2930

3031
<data
3132
android:host="deeplink"
32-
android:scheme="tiamat" />
33+
android:scheme="tiamat"/>
3334
</intent-filter>
3435
</activity>
3536
</application>

example/app/composeApp/src/androidMain/kotlin/composegears/tiamat/example/MainApplication.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package composegears.tiamat.example
33
import android.app.Application
44
import composegears.tiamat.example.extra.A3rdParty
55
import composegears.tiamat.example.platform.Platform
6+
import composegears.tiamat.example.platform.start
67

78
class MainApplication : Application() {
89

example/app/composeApp/src/desktopMain/kotlin/composegears/tiamat/example/main.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import com.composegears.tiamat.LocalNavBackHandler
2323
import composegears.tiamat.example.content.App
2424
import composegears.tiamat.example.extra.A3rdParty
2525
import composegears.tiamat.example.platform.Platform
26+
import composegears.tiamat.example.platform.start
2627

2728
@OptIn(ExperimentalFoundationApi::class)
2829
fun main() {

example/app/composeApp/src/wasmJsMain/kotlin/composegears/tiamat/example/main.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import com.composegears.tiamat.*
1818
import composegears.tiamat.example.content.App
1919
import composegears.tiamat.example.extra.A3rdParty
2020
import composegears.tiamat.example.platform.Platform
21+
import composegears.tiamat.example.platform.start
2122
import composegears.tiamat.example.ui.core.LocalScreenHandler
2223
import composegears.tiamat.example.ui.core.ScreenInfo
2324
import kotlinx.browser.window

example/content/src/commonMain/kotlin/composegears/tiamat/example/content/App.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@ import androidx.compose.foundation.layout.fillMaxSize
44
import androidx.compose.material3.Surface
55
import androidx.compose.runtime.Composable
66
import androidx.compose.ui.Modifier
7-
import com.composegears.tiamat.NavController
8-
import com.composegears.tiamat.Navigation
9-
import com.composegears.tiamat.StorageMode
10-
import com.composegears.tiamat.rememberNavController
7+
import com.composegears.tiamat.*
118
import composegears.tiamat.example.content.content.HomeScreen
129
import composegears.tiamat.example.content.content.advanced.AdvBackStackAlteration
1310
import composegears.tiamat.example.content.content.advanced.AdvExtensions
11+
import composegears.tiamat.example.content.content.advanced.AdvSharedElementTransition
1412
import composegears.tiamat.example.content.content.apr.APRFreeArgs
1513
import composegears.tiamat.example.content.content.apr.APRNavArgs
1614
import composegears.tiamat.example.content.content.apr.APRNavResult
@@ -19,6 +17,7 @@ import composegears.tiamat.example.content.content.architecture.ArchViewModel
1917
import composegears.tiamat.example.content.content.navigation.*
2018
import composegears.tiamat.example.extra.A3rdParty
2119
import composegears.tiamat.example.platform.Platform
20+
import composegears.tiamat.example.platform.features
2221
import composegears.tiamat.example.ui.core.AppTheme
2322

2423
@Composable
@@ -48,13 +47,18 @@ fun App(
4847
ArchCustomSaveState,
4948
AdvExtensions,
5049
AdvBackStackAlteration,
50+
AdvSharedElementTransition,
5151
*(Platform.features() + A3rdParty.features())
5252
.map { it.destination }
5353
.toTypedArray()
5454
),
5555
configuration = navControllerConfig
5656
)
57-
Navigation(rootNavController, Modifier.fillMaxSize())
57+
Navigation(
58+
navController = rootNavController,
59+
modifier = Modifier.fillMaxSize(),
60+
contentTransformProvider = { navigationPlatformDefault(it) }
61+
)
5862
overlay(rootNavController)
5963
}
6064
}

example/content/src/commonMain/kotlin/composegears/tiamat/example/content/content/HomeScreen.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import com.composegears.tiamat.navController
3131
import com.composegears.tiamat.navDestination
3232
import composegears.tiamat.example.content.content.advanced.AdvBackStackAlteration
3333
import composegears.tiamat.example.content.content.advanced.AdvExtensions
34+
import composegears.tiamat.example.content.content.advanced.AdvSharedElementTransition
3435
import composegears.tiamat.example.content.content.apr.APRFreeArgs
3536
import composegears.tiamat.example.content.content.apr.APRNavArgs
3637
import composegears.tiamat.example.content.content.apr.APRNavResult
@@ -39,6 +40,8 @@ import composegears.tiamat.example.content.content.architecture.ArchViewModel
3940
import composegears.tiamat.example.content.content.navigation.*
4041
import composegears.tiamat.example.extra.A3rdParty
4142
import composegears.tiamat.example.platform.Platform
43+
import composegears.tiamat.example.platform.features
44+
import composegears.tiamat.example.platform.name
4245
import composegears.tiamat.example.ui.core.*
4346

4447
private val HomeItems =
@@ -127,6 +130,11 @@ private val HomeItems =
127130
description = "Example shows how to use nav-destination extensions (eg: Analytics tracking)",
128131
destination = AdvExtensions
129132
),
133+
AppFeature(
134+
name = "Shared element transition",
135+
description = "Example shows how to use shared element transition",
136+
destination = AdvSharedElementTransition
137+
),
130138
),
131139
),
132140
HomeItem(
@@ -144,7 +152,10 @@ private val HomeItems =
144152
val HomeScreen: NavDestination<Unit> by navDestination(ScreenInfo("Home")) {
145153
val navController = navController()
146154
Box(
147-
modifier = Modifier.fillMaxSize().systemBarsPadding(),
155+
modifier = Modifier
156+
.fillMaxSize()
157+
.background(MaterialTheme.colorScheme.surface)
158+
.systemBarsPadding(),
148159
contentAlignment = Alignment.Center
149160
) {
150161
var selectedItem by rememberSaveable { mutableStateOf<String?>(null) }
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package composegears.tiamat.example.content.content.advanced
2+
3+
import androidx.compose.animation.ExperimentalSharedTransitionApi
4+
import androidx.compose.animation.SharedTransitionLayout
5+
import androidx.compose.animation.SharedTransitionScope
6+
import androidx.compose.foundation.background
7+
import androidx.compose.foundation.border
8+
import androidx.compose.foundation.layout.*
9+
import androidx.compose.foundation.shape.RoundedCornerShape
10+
import androidx.compose.material.icons.Icons
11+
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
12+
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
13+
import androidx.compose.material3.MaterialTheme
14+
import androidx.compose.material3.Text
15+
import androidx.compose.runtime.CompositionLocalProvider
16+
import androidx.compose.runtime.staticCompositionLocalOf
17+
import androidx.compose.ui.Alignment
18+
import androidx.compose.ui.Modifier
19+
import androidx.compose.ui.graphics.Color
20+
import androidx.compose.ui.unit.dp
21+
import com.composegears.tiamat.*
22+
import composegears.tiamat.example.ui.core.*
23+
24+
@OptIn(ExperimentalSharedTransitionApi::class)
25+
private val LocalSharedTransitionScope = staticCompositionLocalOf<SharedTransitionScope> { error("No scope provided") }
26+
27+
@OptIn(ExperimentalSharedTransitionApi::class)
28+
val AdvSharedElementTransition by navDestination<Unit>(ScreenInfo()) {
29+
Screen("SharedElementTransition") {
30+
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
31+
val nc = rememberNavController(
32+
key = "SharedElementTransition nav controller",
33+
startDestination = AdvSharedElementTransitionScreen1,
34+
destinations = arrayOf(
35+
AdvSharedElementTransitionScreen1,
36+
AdvSharedElementTransitionScreen2,
37+
AdvSharedElementTransitionScreen3,
38+
)
39+
)
40+
SharedTransitionLayout {
41+
CompositionLocalProvider(
42+
LocalSharedTransitionScope provides this
43+
) {
44+
Navigation(
45+
navController = nc,
46+
modifier = Modifier
47+
.fillMaxSize()
48+
.padding(16.dp)
49+
.border(1.dp, MaterialTheme.colorScheme.outlineVariant, RoundedCornerShape(8.dp))
50+
.padding(16.dp),
51+
contentTransformProvider = { navigationSlideInOut(it) }
52+
)
53+
}
54+
}
55+
}
56+
}
57+
}
58+
59+
@OptIn(ExperimentalSharedTransitionApi::class)
60+
private val AdvSharedElementTransitionScreen1 by navDestination<Unit> {
61+
val nc = navController()
62+
Box(Modifier.fillMaxSize().padding(16.dp), contentAlignment = Alignment.Center) {
63+
Column(horizontalAlignment = Alignment.CenterHorizontally) {
64+
Text("Screen 1", style = MaterialTheme.typography.headlineMedium)
65+
VSpacer()
66+
with(LocalSharedTransitionScope.current) {
67+
Text(
68+
"This is SHARED element on screen 1",
69+
modifier = Modifier
70+
.sharedElement(
71+
state = rememberSharedContentState("element"),
72+
animatedVisibilityScope = this@navDestination,
73+
)
74+
.renderInSharedTransitionScopeOverlay()
75+
.animateEnterExit()
76+
.background(Color.Green.copy(alpha = 0.3f))
77+
.padding(16.dp),
78+
style = MaterialTheme.typography.bodyLarge
79+
)
80+
}
81+
VSpacer()
82+
AppButton(
83+
"Next",
84+
endIcon = Icons.AutoMirrored.Default.KeyboardArrowRight,
85+
onClick = { nc.navigate(AdvSharedElementTransitionScreen2) }
86+
)
87+
}
88+
}
89+
}
90+
91+
@OptIn(ExperimentalSharedTransitionApi::class)
92+
private val AdvSharedElementTransitionScreen2 by navDestination<Unit> {
93+
val nc = navController()
94+
Box(Modifier.fillMaxSize().padding(16.dp), contentAlignment = Alignment.Center) {
95+
Column(horizontalAlignment = Alignment.CenterHorizontally) {
96+
Text("Screen 2", style = MaterialTheme.typography.headlineMedium)
97+
VSpacer()
98+
with(LocalSharedTransitionScope.current) {
99+
Text(
100+
"This is SHARED element on screen 2",
101+
modifier = Modifier
102+
.sharedElement(
103+
state = rememberSharedContentState("element"),
104+
animatedVisibilityScope = this@navDestination,
105+
)
106+
.renderInSharedTransitionScopeOverlay()
107+
.animateEnterExit()
108+
.background(Color.Red.copy(alpha = 0.3f))
109+
.padding(16.dp),
110+
style = MaterialTheme.typography.bodyLarge
111+
)
112+
}
113+
VSpacer()
114+
Row {
115+
AppButton(
116+
"Back",
117+
startIcon = Icons.AutoMirrored.Default.KeyboardArrowLeft,
118+
onClick = { nc.back() }
119+
)
120+
HSpacer()
121+
AppButton(
122+
"Next",
123+
endIcon = Icons.AutoMirrored.Default.KeyboardArrowRight,
124+
onClick = { nc.navigate(AdvSharedElementTransitionScreen3) }
125+
)
126+
}
127+
}
128+
}
129+
}
130+
131+
@OptIn(ExperimentalSharedTransitionApi::class)
132+
private val AdvSharedElementTransitionScreen3 by navDestination<Unit> {
133+
val nc = navController()
134+
Box(Modifier.fillMaxSize().padding(16.dp), contentAlignment = Alignment.Center) {
135+
Column(horizontalAlignment = Alignment.CenterHorizontally) {
136+
Text("Screen 3", style = MaterialTheme.typography.headlineMedium)
137+
VSpacer()
138+
with(LocalSharedTransitionScope.current) {
139+
Text(
140+
"This is SHARED element on screen 3",
141+
modifier = Modifier
142+
.sharedElement(
143+
state = rememberSharedContentState("element"),
144+
animatedVisibilityScope = this@navDestination,
145+
)
146+
.renderInSharedTransitionScopeOverlay()
147+
.animateEnterExit()
148+
.background(Color.Blue.copy(alpha = 0.3f))
149+
.padding(16.dp),
150+
style = MaterialTheme.typography.bodyLarge
151+
)
152+
}
153+
VSpacer()
154+
AppButton(
155+
"Back",
156+
startIcon = Icons.AutoMirrored.Default.KeyboardArrowLeft,
157+
onClick = { nc.back() }
158+
)
159+
}
160+
}
161+
}

example/platform/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,8 @@ kotlin {
3535
implementation(projects.tiamat)
3636
implementation(projects.example.uiCore)
3737
}
38+
androidMain.dependencies {
39+
implementation(libs.androidx.activity.compose)
40+
}
3841
}
3942
}

example/platform/src/androidMain/kotlin/composegears/tiamat/example/platform/Platform.android.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ package composegears.tiamat.example.platform
44

55
import composegears.tiamat.example.ui.core.AppFeature
66

7-
actual object Platform {
8-
actual fun start() = Unit
9-
actual fun name(): String = "Android"
10-
actual fun features(): List<AppFeature> = emptyList()
11-
}
7+
actual fun Platform.start() = Unit
8+
actual fun Platform.name(): String = "Android"
9+
actual fun Platform.platformFeatures(): List<AppFeature> = emptyList()

0 commit comments

Comments
 (0)