Skip to content

Commit be00653

Browse files
committed
[optimize] Replace Nav2 with Nav3
1 parent 8c36513 commit be00653

18 files changed

Lines changed: 163 additions & 215 deletions

File tree

gradle/libs.versions.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ compose-materialIconsExtended = "1.7.3"
1313
lifecycle = "2.9.6"
1414
navigation3 = "1.0.1"
1515
ktor = "3.4.0"
16-
koin = "4.1.1"
16+
koin = "4.2.0-RC1"
1717
ksoup = "0.2.5"
1818
coil = "3.3.0"
1919
paging = "3.4.1"
@@ -50,6 +50,7 @@ jetbrains-compose-components-resources = { module = "org.jetbrains.compose.compo
5050

5151
jetbrains-navigation3-ui = { module = "org.jetbrains.androidx.navigation3:navigation3-ui", version = "1.1.0-alpha02" }
5252
jetbrains-lifecycle-viewmodel = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel", version.ref = "lifecycle" }
53+
jetbrains-lifecycle-viewmodel-navigation3 = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-navigation3", version = "2.10.0-alpha08" }
5354
jetbrains-lifecycle-runtime-compose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycle" }
5455

5556
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
@@ -71,7 +72,6 @@ androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version
7172
androidx-paging-common = { module = "androidx.paging:paging-common", version.ref = "paging" }
7273
androidx-paging-compose = { module = "androidx.paging:paging-compose", version.ref = "paging" }
7374
androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "navigation3" }
74-
androidx-lifecycle-viewmodel-navigation3 = { module = "androidx.lifecycle:lifecycle-viewmodel-navigation3", version = "2.10.0" }
7575

7676
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
7777
androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }
@@ -82,7 +82,7 @@ koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
8282
koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" }
8383
koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koin" }
8484
koin-compose-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koin" }
85-
koin-compose-viewmodel-navigation = { module = "io.insert-koin:koin-compose-viewmodel-navigation", version.ref = "koin" }
85+
koin-compose-navigation3 = { module = "io.insert-koin:koin-compose-navigation3", version.ref = "koin" }
8686

8787
kermit = { module = "co.touchlab:kermit", version = "2.0.8" }
8888
kotlincrypto-hash-md = { module = "org.kotlincrypto.hash:md", version = "0.8.0" }
@@ -126,7 +126,7 @@ icu4j = { module = "com.ibm.icu:icu4j", version = "78.1" }
126126
ocpsoft-prettytime = { module = "org.ocpsoft.prettytime:prettytime", version = "5.0.9.Final" }
127127

128128
skyd666-settings = { module = "io.github.skyd666:settings", version = "1.0-beta08" }
129-
skyd666-compone = { module = "io.github.skyd666:compone", version = "1.0-beta21" }
129+
skyd666-compone = { module = "io.github.skyd666:compone", version = "1.0-beta22" }
130130
skyd666-mvi = { module = "io.github.skyd666:mvi", version = "1.0-beta05" }
131131

132132
junit = { module = "junit:junit", version = "4.13.2" }

platform/android/app/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ dependencies {
220220
implementation(libs.koin.android)
221221
implementation(libs.koin.compose)
222222
implementation(libs.koin.compose.viewmodel)
223-
implementation(libs.koin.compose.viewmodel.navigation)
223+
implementation(libs.koin.compose.navigation3)
224224

225225
implementation(libs.kotlinx.coroutines.guava)
226226

shared/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ kotlin {
7474
implementation(libs.jetbrains.compose.materialIconsExtended)
7575
implementation(libs.jetbrains.compose.components.resources)
7676
implementation(libs.jetbrains.lifecycle.viewmodel)
77+
implementation(libs.jetbrains.lifecycle.viewmodel.navigation3)
7778
implementation(libs.jetbrains.lifecycle.runtime.compose)
7879
implementation(libs.jetbrains.navigation3.ui)
7980

@@ -82,11 +83,10 @@ kotlin {
8283
implementation(libs.androidx.paging.compose)
8384
implementation(libs.androidx.constraintlayout.compose)
8485
implementation(libs.androidx.navigation3.runtime)
85-
implementation(libs.androidx.lifecycle.viewmodel.navigation3)
8686

8787
implementation(libs.koin.core)
8888
implementation(libs.koin.compose.viewmodel)
89-
implementation(libs.koin.compose.viewmodel.navigation)
89+
implementation(libs.koin.compose.navigation3)
9090

9191
implementation(libs.kotlinx.coroutines.core)
9292
implementation(libs.kotlinx.serialization.json)

shared/src/commonMain/kotlin/com/skyd/podaura/ui/component/Navigation.kt

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.skyd.podaura.ui.component
22

3+
import androidx.compose.animation.AnimatedContentTransitionScope
4+
import androidx.compose.animation.ContentTransform
35
import androidx.compose.animation.core.FiniteAnimationSpec
46
import androidx.compose.animation.core.tween
57
import androidx.compose.animation.fadeIn
@@ -17,48 +19,28 @@ import androidx.compose.material3.adaptive.layout.PaneScaffoldRole
1719
import androidx.compose.material3.adaptive.layout.PaneScaffoldValue
1820
import androidx.compose.runtime.Composable
1921
import androidx.compose.ui.Modifier
20-
import androidx.compose.ui.Modifier.Companion
2122
import androidx.compose.ui.unit.IntRect
2223
import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator
23-
import androidx.navigation.NavType
2424
import androidx.navigation3.runtime.NavEntry
2525
import androidx.navigation3.runtime.NavEntryDecorator
2626
import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
27+
import androidx.navigation3.scene.Scene
2728
import androidx.navigation3.scene.SceneStrategy
2829
import androidx.navigation3.scene.SinglePaneSceneStrategy
2930
import androidx.navigation3.ui.NavDisplay
30-
import com.skyd.podaura.ui.component.UuidListType.Companion.decodeUuidList
31+
import androidx.navigationevent.NavigationEvent
3132
import com.skyd.podaura.ui.component.navigation.deeplink.TypeParser
3233
import kotlinx.io.Buffer
3334
import kotlinx.io.readByteArray
3435
import kotlinx.serialization.Serializable
3536
import kotlinx.serialization.json.Json
37+
import kotlinx.serialization.json.encodeToJsonElement
3638
import kotlin.io.encoding.Base64
3739
import kotlin.uuid.Uuid
3840

3941

40-
inline fun <reified T> serializableType(
41-
json: Json = Json,
42-
): TypeParser {
43-
return { value ->
44-
json.decodeFromString(value.hexToByteArray().decodeToString())
45-
}
46-
}
47-
48-
inline fun <reified T> listType(
49-
json: Json = Json,
50-
): TypeParser {
51-
return {
52-
serializableType<List<T>>(json)
53-
}
54-
}
55-
5642
@Serializable
57-
data class UuidList(val uuids: List<String>)
58-
59-
abstract class UuidListType<T>(
60-
isNullableAllowed: Boolean = false,
61-
) : NavType<T>(isNullableAllowed) {
43+
data class UuidList(val uuids: List<String>) {
6244
companion object {
6345
fun encodeUuidList(uuidList: List<Uuid>): String {
6446
val buffer = Buffer()
@@ -88,7 +70,7 @@ abstract class UuidListType<T>(
8870

8971
fun uuidListType(): TypeParser {
9072
return { value ->
91-
UuidList(decodeUuidList(value).map { it.toString() })
73+
Json.encodeToJsonElement(UuidList(UuidList.decodeUuidList(value).map { it.toString() }))
9274
}
9375
}
9476

@@ -123,16 +105,27 @@ fun <T : Any> PodAuraNavDisplay(
123105
rememberViewModelStoreNavEntryDecorator()
124106
),
125107
sceneStrategy: SceneStrategy<T> = SinglePaneSceneStrategy(),
108+
transitionSpec: AnimatedContentTransitionScope<Scene<T>>.() -> ContentTransform = {
109+
EnterTransition togetherWith ExitTransition
110+
},
111+
popTransitionSpec: AnimatedContentTransitionScope<Scene<T>>.() -> ContentTransform = {
112+
PopEnterTransition togetherWith PopExitTransition
113+
},
114+
predictivePopTransitionSpec: AnimatedContentTransitionScope<Scene<T>>.(
115+
@NavigationEvent.SwipeEdge Int
116+
) -> ContentTransform = {
117+
PopEnterTransition togetherWith PopExitTransition
118+
},
126119
entryProvider: (key: T) -> NavEntry<T>,
127120
) = NavDisplay(
128121
backStack = backStack,
129122
modifier = modifier.background(MaterialTheme.colorScheme.background),
130123
onBack = onBack,
131124
entryDecorators = entryDecorators,
132125
sceneStrategy = sceneStrategy,
133-
transitionSpec = { EnterTransition togetherWith ExitTransition },
134-
popTransitionSpec = { PopEnterTransition togetherWith PopExitTransition },
135-
predictivePopTransitionSpec = { PopEnterTransition togetherWith PopExitTransition },
126+
transitionSpec = transitionSpec,
127+
popTransitionSpec = popTransitionSpec,
128+
predictivePopTransitionSpec = predictivePopTransitionSpec,
136129
entryProvider = entryProvider,
137130
)
138131

shared/src/commonMain/kotlin/com/skyd/podaura/ui/component/navigation/ExternalUrlHandler.kt

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ import androidx.compose.runtime.DisposableEffect
55
import androidx.navigation3.runtime.NavKey
66
import com.skyd.podaura.ui.component.navigation.deeplink.DeepLinkMatcher
77
import com.skyd.podaura.ui.component.navigation.deeplink.DeepLinkRequest
8-
import com.skyd.podaura.ui.component.navigation.deeplink.KeyDecoder
98
import com.skyd.podaura.ui.screen.deepLinkPatterns
109
import io.ktor.http.URLBuilder
1110
import kotlinx.serialization.SerialName
1211
import kotlinx.serialization.Serializable
12+
import kotlinx.serialization.json.Json
13+
import kotlinx.serialization.json.JsonPrimitive
14+
import kotlinx.serialization.json.buildJsonObject
1315

1416
object ExternalUrlHandler {
1517
// Storage for when a Url arrives before the listener is set up
@@ -83,12 +85,19 @@ internal fun ExternalUrlHandler.UrlData.toNavKey(): NavKey? {
8385
val match = deepLinkPatterns.firstNotNullOfOrNull { pattern ->
8486
DeepLinkMatcher(request, pattern).match()
8587
}
88+
89+
val json = Json {
90+
isLenient = true
91+
ignoreUnknownKeys = true
92+
}
8693
return match?.let {
87-
KeyDecoder(buildMap {
88-
putAll(match.args)
89-
url?.let { put(ExternalUrlHandler.UrlData.URL_NAME, it) }
90-
mimeType?.let { put(ExternalUrlHandler.UrlData.MIMETYPE_NAME, it) }
91-
action?.let { put(ExternalUrlHandler.UrlData.ACTION_NAME, it) }
92-
}).decodeSerializableValue(match.serializer)
94+
json.decodeFromJsonElement(match.serializer, buildJsonObject {
95+
for (entry in match.args) {
96+
put(entry.key, entry.value)
97+
}
98+
url?.let { put(ExternalUrlHandler.UrlData.URL_NAME, JsonPrimitive(it)) }
99+
mimeType?.let { put(ExternalUrlHandler.UrlData.MIMETYPE_NAME, JsonPrimitive(it)) }
100+
action?.let { put(ExternalUrlHandler.UrlData.ACTION_NAME, JsonPrimitive(it)) }
101+
})
93102
}
94103
}

shared/src/commonMain/kotlin/com/skyd/podaura/ui/component/navigation/PodAuraSerializersModule.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import com.skyd.podaura.ui.screen.calendar.CalendarRoute
1010
import com.skyd.podaura.ui.screen.download.DownloadDeepLinkRoute
1111
import com.skyd.podaura.ui.screen.download.DownloadRoute
1212
import com.skyd.podaura.ui.screen.feed.FeedListRoute
13+
import com.skyd.podaura.ui.screen.feed.FeedRoute
1314
import com.skyd.podaura.ui.screen.feed.autodl.AutoDownloadRuleRoute
1415
import com.skyd.podaura.ui.screen.feed.mute.MuteFeedRoute
1516
import com.skyd.podaura.ui.screen.feed.reorder.feed.ReorderFeedRoute
@@ -18,8 +19,11 @@ import com.skyd.podaura.ui.screen.feed.requestheaders.RequestHeadersRoute
1819
import com.skyd.podaura.ui.screen.filepicker.FilePickerRoute
1920
import com.skyd.podaura.ui.screen.history.HistoryRoute
2021
import com.skyd.podaura.ui.screen.history.search.HistorySearchRoute
22+
import com.skyd.podaura.ui.screen.media.MediaRoute
2123
import com.skyd.podaura.ui.screen.media.search.MediaSearchRoute
2224
import com.skyd.podaura.ui.screen.media.sub.SubMediaRoute
25+
import com.skyd.podaura.ui.screen.more.MoreRoute
26+
import com.skyd.podaura.ui.screen.playlist.PlaylistRoute
2327
import com.skyd.podaura.ui.screen.playlist.medialist.PlaylistMediaListRoute
2428
import com.skyd.podaura.ui.screen.read.ReadRoute
2529
import com.skyd.podaura.ui.screen.search.SearchRoute
@@ -50,8 +54,10 @@ import kotlinx.serialization.modules.subclass
5054
val PodAuraSerializersModule = SerializersModule {
5155
polymorphic(baseClass = NavKey::class) {
5256
subclass(MainRoute::class)
57+
subclass(FeedRoute::class)
5358
subclass(FeedListRoute::class)
5459
subclass(ArticleRoute::class)
60+
subclass(MoreRoute::class)
5561
subclass(LicenseRoute::class)
5662
subclass(AboutRoute::class)
5763
subclass(TermsOfServiceRoute::class)
@@ -80,6 +86,7 @@ val PodAuraSerializersModule = SerializersModule {
8086
subclass(AutoDownloadRuleRoute::class)
8187
subclass(MuteFeedRoute::class)
8288
subclass(DeleteConstraintRoute::class)
89+
subclass(PlaylistRoute::class)
8390
subclass(PlaylistMediaListRoute::class)
8491
subclass(RequestHeadersRoute::class)
8592
subclass(FilePickerRoute::class)
@@ -88,6 +95,7 @@ val PodAuraSerializersModule = SerializersModule {
8895
subclass(ReadRoute::class)
8996
subclass(SearchRoute.Feed::class)
9097
subclass(SearchRoute.Article::class)
98+
subclass(MediaRoute::class)
9199
subclass(MediaSearchRoute::class)
92100
subclass(SubMediaRoute::class)
93101
subclass(HistorySearchRoute::class)

shared/src/commonMain/kotlin/com/skyd/podaura/ui/component/navigation/deeplink/DeepLinkMatcher.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import androidx.navigation3.runtime.NavKey
44
import co.touchlab.kermit.Logger
55
import io.ktor.http.authority
66
import kotlinx.serialization.KSerializer
7+
import kotlinx.serialization.json.JsonElement
8+
import kotlinx.serialization.json.JsonObject
79

810
internal class DeepLinkMatcher<T : NavKey>(
911
val request: DeepLinkRequest,
@@ -44,12 +46,12 @@ internal class DeepLinkMatcher<T : NavKey>(
4446
}
4547
// exact match (url does not contain any arguments)
4648
if (request.uri == deepLinkPattern.urlPattern) {
47-
return DeepLinkMatchResult(deepLinkPattern.serializer, mapOf())
49+
return DeepLinkMatchResult(deepLinkPattern.serializer, JsonObject(mapOf()))
4850
}
4951
}
5052
}
5153

52-
val args = mutableMapOf<String, Any>()
54+
val args = mutableMapOf<String, JsonElement>()
5355
// match the path
5456
request.pathSegments
5557
.asSequence()
@@ -91,7 +93,7 @@ internal class DeepLinkMatcher<T : NavKey>(
9193
args[name] = queryParsedValue
9294
}
9395
// provide the serializer of the matching key and map of arg names to parsed arg values
94-
return DeepLinkMatchResult(deepLinkPattern.serializer, args)
96+
return DeepLinkMatchResult(deepLinkPattern.serializer, JsonObject(args))
9597
}
9698
}
9799

@@ -101,11 +103,9 @@ internal class DeepLinkMatcher<T : NavKey>(
101103
*
102104
* @param [T] the backstack key associated with the deeplink that matched with the requested deeplink
103105
* @param serializer serializer for [T]
104-
* @param args The map of argument name to argument value. The value is expected to have already
105-
* been parsed from the raw url string back into its proper KType as declared in [T].
106-
* Includes arguments for all parts of the uri - path, query, etc.
106+
* @param args The JsonObject of argument name to argument value.
107107
* */
108108
internal data class DeepLinkMatchResult<T : NavKey>(
109109
val serializer: KSerializer<T>,
110-
val args: Map<String, Any>
110+
val args: JsonObject
111111
)

shared/src/commonMain/kotlin/com/skyd/podaura/ui/component/navigation/deeplink/DeepLinkPattern.kt

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
package com.skyd.podaura.ui.component.navigation.deeplink
22

33
import androidx.navigation3.runtime.NavKey
4+
import com.skyd.podaura.util.from
45
import io.ktor.http.Url
56
import kotlinx.serialization.KSerializer
67
import kotlinx.serialization.descriptors.PrimitiveKind
78
import kotlinx.serialization.descriptors.SerialKind
9+
import kotlinx.serialization.descriptors.StructureKind
810
import kotlinx.serialization.encoding.CompositeDecoder
11+
import kotlinx.serialization.json.JsonArray
12+
import kotlinx.serialization.json.JsonElement
13+
import kotlinx.serialization.json.JsonPrimitive
914

1015
/**
1116
* Parse a supported deeplink and stores its metadata as a easily readable format
@@ -112,26 +117,27 @@ class DeepLinkPattern<T : NavKey>(
112117
}
113118

114119
/**
115-
* Parses a String into a Primitive
120+
* Parses a String into a JsonElement
116121
*/
117-
typealias TypeParser = (String) -> Any
122+
typealias TypeParser = (String) -> JsonElement
118123

119124
private fun getTypeParser(kind: SerialKind, additional: Map<SerialKind, TypeParser>): TypeParser {
120-
additional[kind]?.let {
121-
return it
122-
}
125+
additional[kind]?.let { return it }
123126
return when (kind) {
124-
PrimitiveKind.STRING -> Any::toString
125-
PrimitiveKind.INT -> String::toInt
126-
PrimitiveKind.BOOLEAN -> String::toBoolean
127-
PrimitiveKind.BYTE -> String::toByte
128-
PrimitiveKind.CHAR -> String::toCharArray
129-
PrimitiveKind.DOUBLE -> String::toDouble
130-
PrimitiveKind.FLOAT -> String::toFloat
131-
PrimitiveKind.LONG -> String::toLong
132-
PrimitiveKind.SHORT -> String::toShort
127+
PrimitiveKind.STRING -> ::JsonPrimitive
128+
PrimitiveKind.INT -> ::JsonPrimitive
129+
PrimitiveKind.BOOLEAN -> ::JsonPrimitive
130+
PrimitiveKind.DOUBLE -> ::JsonPrimitive
131+
PrimitiveKind.FLOAT -> ::JsonPrimitive
132+
PrimitiveKind.LONG -> ::JsonPrimitive
133+
PrimitiveKind.SHORT -> ::JsonPrimitive
134+
StructureKind.LIST -> { value: Any? ->
135+
val list = value as? List<*> ?: throw IllegalArgumentException("Expected List")
136+
JsonArray.from(list)
137+
}
138+
133139
else -> throw IllegalArgumentException(
134-
"Unsupported argument type of SerialKind:$kind. The argument type must be a Primitive."
140+
"Unsupported argument type of SerialKind:$kind. The argument type must be a Primitive or in the additional."
135141
)
136142
}
137143
}

0 commit comments

Comments
 (0)