From 7cd8eb06ee271f7106e67597e0c48ccd16b2dd3c Mon Sep 17 00:00:00 2001 From: Adetunji Dahunsi Date: Mon, 26 May 2025 11:16:09 -0400 Subject: [PATCH 1/4] Fix Modifier.fillMaxConstraints() --- .../compose/DecoratedNavEntryMultiPaneDisplayScope.kt | 3 +++ .../moveablesharedelement/MovableSharedElements.kt | 10 ++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/DecoratedNavEntryMultiPaneDisplayScope.kt b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/DecoratedNavEntryMultiPaneDisplayScope.kt index 86d579e..d3e844c 100644 --- a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/DecoratedNavEntryMultiPaneDisplayScope.kt +++ b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/DecoratedNavEntryMultiPaneDisplayScope.kt @@ -52,6 +52,9 @@ internal fun DecoratedNavEntr val navigationState by state.navigationState val backStack = remember { mutableStateListOf() }.also { mutableBackStack -> state.backStackTransform(navigationState).let { currentBackStack -> + val sameBackStack = currentBackStack == mutableBackStack + if (sameBackStack) return@let + mutableBackStack.clear() mutableBackStack.addAll(currentBackStack) } diff --git a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/moveablesharedelement/MovableSharedElements.kt b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/moveablesharedelement/MovableSharedElements.kt index c09a956..f55184b 100644 --- a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/moveablesharedelement/MovableSharedElements.kt +++ b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/moveablesharedelement/MovableSharedElements.kt @@ -270,8 +270,14 @@ private fun Modifier.fillMaxConstraints() = layout { measurable, constraints -> val placeable = measurable.measure( constraints.copy( - minWidth = constraints.maxWidth, - maxHeight = constraints.maxHeight + minWidth = when { + constraints.hasBoundedWidth -> constraints.maxWidth + else -> constraints.minWidth + }, + minHeight = when { + constraints.hasBoundedHeight -> constraints.maxHeight + else -> constraints.minHeight + } ) ) layout( From 3635c1e5a08e251e955681d66d672421bca87d38 Mon Sep 17 00:00:00 2001 From: Adetunji Dahunsi Date: Mon, 26 May 2025 12:34:07 -0400 Subject: [PATCH 2/4] Add methods for creating a simple route with tests --- .../com/tunjid/treenav/strings/Route.kt | 61 +++++++++++++- .../tunjid/treenav/strings/RouteMatcher.kt | 22 ++++- .../com/tunjid/treenav/strings/RouteTrie.kt | 9 +- .../src/commonTest/kotlin/RouteMatcherTest.kt | 10 +-- .../src/commonTest/kotlin/RouteTrieTest.kt | 82 +++++++++++++++++++ 5 files changed, 173 insertions(+), 11 deletions(-) create mode 100644 library/strings/src/commonTest/kotlin/RouteTrieTest.kt diff --git a/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/Route.kt b/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/Route.kt index 91f9c47..822d0e8 100644 --- a/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/Route.kt +++ b/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/Route.kt @@ -61,7 +61,64 @@ fun routeString( } } +/** + * Creates a [Route] containing the specified [params] and [children]. + */ +fun routeOf( + params: RouteParams, + children: List = emptyList(), +): Route = BasicRoute( + routeParams = params, + children = children +) + +/** + * Creates a [Route] by combining the [path], [pathArgs] and [queryParams] + * into [RouteParams] with the specified [children]. + */ +@Suppress("unused") +fun routeOf( + path: String, + pathArgs: Map = emptyMap(), + queryParams: Map> = emptyMap(), + children: List = listOf(), +): Route = BasicRoute( + path = path, + pathArgs = pathArgs, + queryParams = queryParams, + children = children +) -fun interface RouteParser { - fun parse(pathAndQueries: String): Route? +/** + * Basic route definition + */ +private class BasicRoute( + override val routeParams: RouteParams, + override val children: List = emptyList(), +) : Route { + + constructor( + path: String, + pathArgs: Map = emptyMap(), + queryParams: Map> = emptyMap(), + children: List = emptyList(), + ) : this( + routeParams = RouteParams( + pathAndQueries = path, + pathArgs = pathArgs, + queryParams = queryParams, + ), + children = children + ) + + override fun toString(): String = id + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Route) return false + + return id == other.id + } + + override fun hashCode(): Int = id.hashCode() } + diff --git a/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/RouteMatcher.kt b/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/RouteMatcher.kt index 4e71ef7..c10a3b3 100644 --- a/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/RouteMatcher.kt +++ b/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/RouteMatcher.kt @@ -17,13 +17,33 @@ package com.tunjid.treenav.strings /** - * Matches route [String] representations into concrete [Route] instances + * Matches a specific [pattern] to a specific [Route]. */ interface RouteMatcher { + + /** + * The [pattern] describing the general form of the [Route] to match. + */ val pattern: PathPattern + + /** + * Creates a [Route] from the parsed parameter parameters. + */ fun route(params: RouteParams): Route } +/** + * Parses urls to create [Route] instances. + */ +fun interface RouteParser { + + /** + * Given a url [pathAndQueries] defining a navigation [Route], this method attempts to create + * the matching [Route] for it, otherwise it returns null. + */ + fun parse(pathAndQueries: String): Route? +} + /** * Creates a [RouteParser] from a list of [RouteMatcher]s. * Note that the order of [RouteMatcher]s matter; place more specific matchers first. diff --git a/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/RouteTrie.kt b/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/RouteTrie.kt index 9d71c0d..a90b965 100644 --- a/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/RouteTrie.kt +++ b/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/RouteTrie.kt @@ -19,7 +19,6 @@ package com.tunjid.treenav.strings /** * A class for looking up items that match a certain path pattern by route */ -@Suppress("unused") class RouteTrie { private val rootTrieNode = TrieNode() @@ -32,4 +31,12 @@ class RouteTrie { operator fun get(route: Route): T? = rootTrieNode.find( path = route.id, ) +} + +/** + * Converts this [Map] to a [RouteTrie] capable of looking up any type [T] by matching it + * to it's [PathPattern]. + */ +fun Map.toRouteTrie() = RouteTrie().apply { + forEach { (pattern, value) -> set(pattern, value) } } \ No newline at end of file diff --git a/library/strings/src/commonTest/kotlin/RouteMatcherTest.kt b/library/strings/src/commonTest/kotlin/RouteMatcherTest.kt index 5d57978..71dbf90 100644 --- a/library/strings/src/commonTest/kotlin/RouteMatcherTest.kt +++ b/library/strings/src/commonTest/kotlin/RouteMatcherTest.kt @@ -14,17 +14,13 @@ * limitations under the License. */ -import com.tunjid.treenav.strings.Route -import com.tunjid.treenav.strings.RouteParams +import com.tunjid.treenav.strings.routeOf import com.tunjid.treenav.strings.routeParserFrom import com.tunjid.treenav.strings.routeString import com.tunjid.treenav.strings.urlRouteMatcher import kotlin.test.Test import kotlin.test.assertEquals -data class TestRoute( - override val routeParams: RouteParams -) : Route class UrlRouteMatcherTest { @@ -33,7 +29,7 @@ class UrlRouteMatcherTest { val routeParser = routeParserFrom( urlRouteMatcher( routePattern = "/users/{id}", - routeMapper = ::TestRoute + routeMapper = ::routeOf ) ) val route = routeParser.parse("/users/jeff") @@ -53,7 +49,7 @@ class UrlRouteMatcherTest { val routeParser = routeParserFrom( urlRouteMatcher( routePattern = "/users/{id}", - routeMapper = ::TestRoute + routeMapper = ::routeOf ) ) val routeString = routeString( diff --git a/library/strings/src/commonTest/kotlin/RouteTrieTest.kt b/library/strings/src/commonTest/kotlin/RouteTrieTest.kt new file mode 100644 index 0000000..9677054 --- /dev/null +++ b/library/strings/src/commonTest/kotlin/RouteTrieTest.kt @@ -0,0 +1,82 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import com.tunjid.treenav.strings.PathPattern +import com.tunjid.treenav.strings.routeOf +import com.tunjid.treenav.strings.toRouteTrie +import kotlin.test.Test +import kotlin.test.assertEquals + + +class RouteTrieTest { + + @Test + fun testReTrieVal() { + val patterns = listOf( + "/users", + "/users/{id}", + "/users/{id}/photos/grid", + "/users/{id}/photos/pager", + "/home", + "/settings", + "/sign-in", + ).map(::PathPattern) + + val routeTrie = patterns + .mapIndexed { index, pattern -> + pattern to index + } + .toMap() + .toRouteTrie() + + assertEquals( + expected = 0, + actual = routeTrie[routeOf("users")], + message = "users path should be found at index 0", + ) + assertEquals( + expected = 1, + actual = routeTrie[routeOf("users/1")], + message = "users path with parameter should be found at index 1", + ) + assertEquals( + expected = null, + actual = routeTrie[routeOf("users/1/photos")], + message = "users path with photos suffix parameter should not be found", + ) + assertEquals( + expected = 2, + actual = routeTrie[routeOf("users/1/photos/grid")], + message = "users path with parameter and photos and grid segments should be found at index 2", + ) + assertEquals( + expected = 3, + actual = routeTrie[routeOf("users/1/photos/pager")], + message = "users path with parameter and photos and pager segments should be found at index 3", + + ) + assertEquals( + expected = null, + actual = routeTrie[routeOf("users/1/photos/pager/oops")], + message = "users path with 'o' parameter suffix should not be found", + ) + assertEquals( + expected = 3, + actual = routeTrie[routeOf("users/1/photos/pager?page=0")], + message = "users path with parameter and photos and pager segments with queries should be found at index 3", + ) + } +} From 5db746066673ae92c2db2107b25b90f74a005aa3 Mon Sep 17 00:00:00 2001 From: Adetunji Dahunsi Date: Mon, 26 May 2025 13:43:29 -0400 Subject: [PATCH 3/4] Made it easier to read values from routes --- .../tunjid/treenav/strings/RouteDelegate.kt | 102 ++++++++++++ .../commonTest/kotlin/RouteDelegateTest.kt | 155 ++++++++++++++++++ 2 files changed, 257 insertions(+) create mode 100644 library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/RouteDelegate.kt create mode 100644 library/strings/src/commonTest/kotlin/RouteDelegateTest.kt diff --git a/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/RouteDelegate.kt b/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/RouteDelegate.kt new file mode 100644 index 0000000..5e6bb1a --- /dev/null +++ b/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/RouteDelegate.kt @@ -0,0 +1,102 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.tunjid.treenav.strings + +import kotlin.properties.ReadOnlyProperty +import kotlin.reflect.KProperty + +private class RouteDelegate( + private val isOptional: Boolean, + private val isPath: Boolean, + private val default: T? = null, + private val mapper: (String) -> T, +) : ReadOnlyProperty { + @Suppress("UNCHECKED_CAST") + override operator fun getValue( + thisRef: Route, + property: KProperty<*> + ): T = when (val value = when { + isPath -> thisRef.routeParams.pathArgs[property.name] + else -> thisRef.routeParams.queryParams[property.name]?.firstOrNull() + }) { + null -> when { + isOptional -> default + else -> default ?: throw NoSuchElementException( + "There is no value for the property '${property.name}' in the Route's ${if(isPath) "path arguments" else "query parameters"}." + ) + } + + else -> mapper(value) + } as T +} + +fun routePath( + default: String? = null +): ReadOnlyProperty = RouteDelegate( + isOptional = false, + isPath = true, + default = default, + mapper = { it } +) + +fun mappedRoutePath( + default: T? = null, + mapper: (String) -> T, +): ReadOnlyProperty = RouteDelegate( + isOptional = false, + isPath = true, + default = default, + mapper = mapper +) + +fun routeQuery( + default: String? = null +): ReadOnlyProperty = RouteDelegate( + isOptional = false, + isPath = false, + default = default, + mapper = { it } +) + +fun mappedRouteQuery( + default: T? = null, + mapper: (String) -> T, +): ReadOnlyProperty = RouteDelegate( + isOptional = false, + isPath = false, + default = default, + mapper = mapper +) + +fun optionalRouteQuery( + default: String? = null +): ReadOnlyProperty = RouteDelegate( + isOptional = true, + isPath = false, + default = default, + mapper = { it } +) + +fun optionalMappedRouteQuery( + default: T? = null, + mapper: (String) -> T, +): ReadOnlyProperty = RouteDelegate( + isOptional = true, + isPath = false, + default = default, + mapper = mapper +) \ No newline at end of file diff --git a/library/strings/src/commonTest/kotlin/RouteDelegateTest.kt b/library/strings/src/commonTest/kotlin/RouteDelegateTest.kt new file mode 100644 index 0000000..8467666 --- /dev/null +++ b/library/strings/src/commonTest/kotlin/RouteDelegateTest.kt @@ -0,0 +1,155 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import com.tunjid.treenav.strings.Route +import com.tunjid.treenav.strings.mappedRoutePath +import com.tunjid.treenav.strings.mappedRouteQuery +import com.tunjid.treenav.strings.optionalMappedRouteQuery +import com.tunjid.treenav.strings.optionalRouteQuery +import com.tunjid.treenav.strings.routeOf +import com.tunjid.treenav.strings.routePath +import com.tunjid.treenav.strings.routeQuery +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith + + +class RouteDelegateTest { + + @Test + fun testDelegateReading() { + + val route = routeOf( + path = "users", + pathArgs = mapOf( + "userId" to "1" + ), + queryParams = mapOf( + "page" to listOf("0"), + "offset" to listOf("10"), + ), + ) + + assertEquals( + expected = 1, + actual = route.userId, + ) + + assertEquals( + expected = 0, + actual = route.page, + ) + + assertEquals( + expected = "10", + actual = route.offset, + ) + + assertEquals( + expected = 100, + actual = route.count, + ) + + assertEquals( + expected = "profilePictures", + actual = route.category, + ) + } + + @Test + fun testDelegateDefaults() { + val route = routeOf( + path = "users", + ) + + assertEquals( + expected = "2", + actual = route.defaultProfileId, + ) + assertEquals( + expected = 20, + actual = route.defaultPage, + ) + + assertEquals( + expected = "200", + actual = route.defaultOffset, + ) + } + + @Test + fun testDelegateExceptions() { + val route = routeOf( + path = "users", + ) + + assertFailsWith { + route.userId + } + assertFailsWith { + route.profileId + } + assertFailsWith { + route.page + } + assertFailsWith { + route.offset + } + + assertEquals( + expected = 100, + actual = route.count, + ) + + assertEquals( + expected = "profilePictures", + actual = route.category, + ) + } +} + +private val Route.userId by mappedRoutePath( + mapper = String::toInt, +) + +private val Route.profileId by routePath() + +private val Route.page by mappedRouteQuery( + mapper = String::toInt, +) + +private val Route.offset by routeQuery() + +private val Route.count by optionalMappedRouteQuery( + mapper = String::toInt, + default = 100, +) + +private val Route.category by optionalRouteQuery( + default = "profilePictures" +) + +private val Route.defaultProfileId by routePath("2") + +private val Route.defaultPage by mappedRouteQuery( + default = 20, + mapper = String::toInt, +) + +private val Route.defaultOffset by routeQuery( + default = "200", +) + From 362b122c1c94f8e3abbae6ac7ab2c38fd5ff7b01 Mon Sep 17 00:00:00 2001 From: Adetunji Dahunsi Date: Mon, 26 May 2025 14:08:33 -0400 Subject: [PATCH 4/4] Version bump --- .../kotlin/android-app-library-convention.kt | 1 - .../src/main/kotlin/kotlin-jvm-convention.kt | 1 - .../kotlin-library-convention.gradle.kts | 3 --- .../treenav/compose/threepane/ThreePane.kt | 10 +++++----- .../transforms/ThreePaneAdaptiveTransform.kt | 2 +- .../com/tunjid/treenav/compose/Defaults.kt | 6 +++--- .../treenav/compose/MultiPaneDisplayState.kt | 1 - .../com/tunjid/treenav/compose/PaneEntry.kt | 2 +- .../com/tunjid/treenav/compose/StackNavExt.kt | 4 ++-- .../treenav/compose/navigation3/NavEntry.kt | 7 ++++--- .../compose/navigation3/NavEntryWrapper.kt | 2 +- .../ViewModelStoreNavEntryDecorator.kt | 3 ++- .../treenav/compose/transforms/Transforms.kt | 2 +- .../SlotBasedAdaptiveNavigationStateTest.kt | 2 +- .../tunjid/treenav/compose/StackNavExtTest.kt | 19 +++++++------------ .../src/main/res/values/AndroidManifest.xml | 3 +-- .../tunjid/treenav/strings/RouteDelegate.kt | 2 +- .../kotlin/com/tunjid/treenav/StackNav.kt | 2 +- .../commonTest/kotlin/MultiStackNavTest.kt | 2 +- .../src/commonTest/kotlin/StackNavTest.kt | 2 +- libraryVersion.properties | 8 ++++---- .../com/tunjid/demo/common/ui/DragToPop.kt | 1 - .../com/tunjid/demo/common/ui/PaneScaffold.kt | 5 +++-- .../demo/common/ui/avatar/AvatarScreen.kt | 2 -- sample/common/src/iosMain/kotlin/main.ios.kt | 2 +- .../jvmMain/kotlin/com/tunjid/demo/Main.kt | 2 +- 26 files changed, 42 insertions(+), 54 deletions(-) diff --git a/build-logic/convention/src/main/kotlin/android-app-library-convention.kt b/build-logic/convention/src/main/kotlin/android-app-library-convention.kt index 512f675..e2cacaa 100644 --- a/build-logic/convention/src/main/kotlin/android-app-library-convention.kt +++ b/build-logic/convention/src/main/kotlin/android-app-library-convention.kt @@ -16,7 +16,6 @@ import com.android.build.api.dsl.CommonExtension import org.gradle.api.JavaVersion -import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.VersionCatalogsExtension /* diff --git a/build-logic/convention/src/main/kotlin/kotlin-jvm-convention.kt b/build-logic/convention/src/main/kotlin/kotlin-jvm-convention.kt index cd710a8..70024b1 100644 --- a/build-logic/convention/src/main/kotlin/kotlin-jvm-convention.kt +++ b/build-logic/convention/src/main/kotlin/kotlin-jvm-convention.kt @@ -14,7 +14,6 @@ * limitations under the License. */ -import org.gradle.api.Action import org.gradle.api.JavaVersion import org.gradle.api.plugins.JavaPluginExtension import org.gradle.kotlin.dsl.configure diff --git a/build-logic/convention/src/main/kotlin/kotlin-library-convention.gradle.kts b/build-logic/convention/src/main/kotlin/kotlin-library-convention.gradle.kts index d4f69b1..7f31044 100644 --- a/build-logic/convention/src/main/kotlin/kotlin-library-convention.gradle.kts +++ b/build-logic/convention/src/main/kotlin/kotlin-library-convention.gradle.kts @@ -14,9 +14,6 @@ * limitations under the License. */ -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget -import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension - /* * Copyright 2021 Google LLC * diff --git a/library/compose-threepane/src/commonMain/kotlin/com/tunjid/treenav/compose/threepane/ThreePane.kt b/library/compose-threepane/src/commonMain/kotlin/com/tunjid/treenav/compose/threepane/ThreePane.kt index 8a9e51d..877bd12 100644 --- a/library/compose-threepane/src/commonMain/kotlin/com/tunjid/treenav/compose/threepane/ThreePane.kt +++ b/library/compose-threepane/src/commonMain/kotlin/com/tunjid/treenav/compose/threepane/ThreePane.kt @@ -126,11 +126,11 @@ fun threePaneEntry( } Box( modifier = - if (shouldAnimate) Modifier.animateEnterExit( - enter = enterTransition(), - exit = exitTransition() - ) - else Modifier, + if (shouldAnimate) Modifier.animateEnterExit( + enter = enterTransition(), + exit = exitTransition() + ) + else Modifier, content = { original(destination) } diff --git a/library/compose-threepane/src/commonMain/kotlin/com/tunjid/treenav/compose/threepane/transforms/ThreePaneAdaptiveTransform.kt b/library/compose-threepane/src/commonMain/kotlin/com/tunjid/treenav/compose/threepane/transforms/ThreePaneAdaptiveTransform.kt index 3656215..b13bca2 100644 --- a/library/compose-threepane/src/commonMain/kotlin/com/tunjid/treenav/compose/threepane/transforms/ThreePaneAdaptiveTransform.kt +++ b/library/compose-threepane/src/commonMain/kotlin/com/tunjid/treenav/compose/threepane/transforms/ThreePaneAdaptiveTransform.kt @@ -24,9 +24,9 @@ import androidx.compose.runtime.remember import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.tunjid.treenav.Node +import com.tunjid.treenav.compose.threepane.ThreePane import com.tunjid.treenav.compose.transforms.PaneTransform import com.tunjid.treenav.compose.transforms.Transform -import com.tunjid.treenav.compose.threepane.ThreePane /** * An [Transform] that selectively displays panes for a [ThreePane] layout diff --git a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/Defaults.kt b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/Defaults.kt index 2f8c5f2..18a1efb 100644 --- a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/Defaults.kt +++ b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/Defaults.kt @@ -34,13 +34,13 @@ import androidx.compose.ui.unit.LayoutDirection @Stable internal object Defaults { - val EmptyElement: @Composable (Any?, Modifier) -> Unit = { _, _ -> } + val EmptyElement: @Composable (Any?, Modifier) -> Unit = { _, _ -> } @ExperimentalSharedTransitionApi - val DefaultBoundsTransform = BoundsTransform { _, _ -> DefaultSpring } + val DefaultBoundsTransform = BoundsTransform { _, _ -> DefaultSpring } @ExperimentalSharedTransitionApi - val ParentClip: OverlayClip = + val ParentClip: OverlayClip = object : OverlayClip { override fun getClipPath( sharedContentState: SharedContentState, diff --git a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/MultiPaneDisplayState.kt b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/MultiPaneDisplayState.kt index 2fa3a0e..0e39bee 100644 --- a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/MultiPaneDisplayState.kt +++ b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/MultiPaneDisplayState.kt @@ -18,7 +18,6 @@ package com.tunjid.treenav.compose import androidx.compose.runtime.Composable import androidx.compose.runtime.State -import androidx.compose.runtime.derivedStateOf import com.tunjid.treenav.Node import com.tunjid.treenav.compose.transforms.CompoundTransform import com.tunjid.treenav.compose.transforms.DestinationTransform diff --git a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/PaneEntry.kt b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/PaneEntry.kt index 7caeea5..7923ecf 100644 --- a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/PaneEntry.kt +++ b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/PaneEntry.kt @@ -12,6 +12,6 @@ import com.tunjid.treenav.compose.transforms.RenderTransform @Stable class PaneEntry( internal val renderTransform: RenderTransform, - internal val paneTransform: @Composable (Destination) -> Map, + internal val paneTransform: @Composable (Destination) -> Map, internal val content: @Composable PaneScope.(Destination) -> Unit, ) \ No newline at end of file diff --git a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/StackNavExt.kt b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/StackNavExt.kt index 87a7f56..89b29af 100644 --- a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/StackNavExt.kt +++ b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/StackNavExt.kt @@ -25,7 +25,7 @@ import com.tunjid.treenav.backStack * A convenience method for reading the back stack for this [MultiStackNav] * optimized for consumption for a [MultiPaneDisplay]. */ -inline fun MultiStackNav.multiPaneDisplayBackstack(): List = +inline fun MultiStackNav.multiPaneDisplayBackstack(): List = backStack( includeCurrentDestinationChildren = true, placeChildrenBeforeParent = true, @@ -37,7 +37,7 @@ inline fun MultiStackNav.multiPaneDisplayBackstack() * A convenience method for reading the back stack for this [MultiStackNav] * optimized for consumption for a [MultiPaneDisplay]. */ -inline fun StackNav.multiPaneDisplayBackstack(): List = +inline fun StackNav.multiPaneDisplayBackstack(): List = backStack( includeCurrentDestinationChildren = true, placeChildrenBeforeParent = true, diff --git a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/navigation3/NavEntry.kt b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/navigation3/NavEntry.kt index 9416ac9..8a40bae 100644 --- a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/navigation3/NavEntry.kt +++ b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/navigation3/NavEntry.kt @@ -15,6 +15,7 @@ */ package com.tunjid.treenav.compose.navigation3 + import androidx.compose.runtime.Composable /** @@ -26,7 +27,7 @@ import androidx.compose.runtime.Composable * @param content content for this entry to be displayed when this entry is active */ internal open class NavEntry( - public open val key: T, - public open val metadata: Map = emptyMap(), - public open val content: @Composable (T) -> Unit + open val key: T, + open val metadata: Map = emptyMap(), + open val content: @Composable (T) -> Unit ) diff --git a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/navigation3/NavEntryWrapper.kt b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/navigation3/NavEntryWrapper.kt index 35a8d35..2813c9e 100644 --- a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/navigation3/NavEntryWrapper.kt +++ b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/navigation3/NavEntryWrapper.kt @@ -25,7 +25,7 @@ import androidx.compose.runtime.Composable * * @param navEntry the [NavEntry] to wrap */ -internal open class NavEntryWrapper(public val navEntry: NavEntry) : +internal open class NavEntryWrapper(val navEntry: NavEntry) : NavEntry(navEntry.key, navEntry.metadata, navEntry.content) { override val key: T get() = navEntry.key diff --git a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/navigation3/decorators/ViewModelStoreNavEntryDecorator.kt b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/navigation3/decorators/ViewModelStoreNavEntryDecorator.kt index 2bdd320..7153277 100644 --- a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/navigation3/decorators/ViewModelStoreNavEntryDecorator.kt +++ b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/navigation3/decorators/ViewModelStoreNavEntryDecorator.kt @@ -39,7 +39,8 @@ import androidx.savedstate.compose.LocalSavedStateRegistryOwner import com.tunjid.treenav.compose.navigation3.NavEntryDecorator import com.tunjid.treenav.compose.navigation3.navEntryDecorator -@Composable internal expect fun shouldRemoveViewModelStoreCallback(): () -> Boolean +@Composable +internal expect fun shouldRemoveViewModelStoreCallback(): () -> Boolean internal expect fun SavedStateViewModelFactory( savedStateRegistryOwner: SavedStateRegistryOwner diff --git a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/transforms/Transforms.kt b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/transforms/Transforms.kt index a7078be..a79ccc7 100644 --- a/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/transforms/Transforms.kt +++ b/library/compose/src/commonMain/kotlin/com/tunjid/treenav/compose/transforms/Transforms.kt @@ -2,9 +2,9 @@ package com.tunjid.treenav.compose.transforms import androidx.compose.runtime.Composable import com.tunjid.treenav.Node -import com.tunjid.treenav.compose.PaneScope import com.tunjid.treenav.compose.MultiPaneDisplay import com.tunjid.treenav.compose.MultiPaneDisplayState +import com.tunjid.treenav.compose.PaneScope /** * Provides APIs for adjusting what is presented in a [MultiPaneDisplay]. diff --git a/library/compose/src/commonTest/kotlin/com/tunjid/treenav/compose/SlotBasedAdaptiveNavigationStateTest.kt b/library/compose/src/commonTest/kotlin/com/tunjid/treenav/compose/SlotBasedAdaptiveNavigationStateTest.kt index 3b5594c..19cff24 100644 --- a/library/compose/src/commonTest/kotlin/com/tunjid/treenav/compose/SlotBasedAdaptiveNavigationStateTest.kt +++ b/library/compose/src/commonTest/kotlin/com/tunjid/treenav/compose/SlotBasedAdaptiveNavigationStateTest.kt @@ -19,9 +19,9 @@ package com.tunjid.treenav.compose import com.tunjid.treenav.Node import com.tunjid.treenav.StackNav import com.tunjid.treenav.backStack -import com.tunjid.treenav.requireCurrent import com.tunjid.treenav.pop import com.tunjid.treenav.push +import com.tunjid.treenav.requireCurrent import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals diff --git a/library/compose/src/commonTest/kotlin/com/tunjid/treenav/compose/StackNavExtTest.kt b/library/compose/src/commonTest/kotlin/com/tunjid/treenav/compose/StackNavExtTest.kt index 3d312a4..1e9841f 100644 --- a/library/compose/src/commonTest/kotlin/com/tunjid/treenav/compose/StackNavExtTest.kt +++ b/library/compose/src/commonTest/kotlin/com/tunjid/treenav/compose/StackNavExtTest.kt @@ -17,19 +17,12 @@ package com.tunjid.treenav.compose import com.tunjid.treenav.MultiStackNav -import com.tunjid.treenav.Node import com.tunjid.treenav.StackNav import com.tunjid.treenav.backStack -import com.tunjid.treenav.requireCurrent -import com.tunjid.treenav.pop import com.tunjid.treenav.push -import com.tunjid.treenav.reversedBackStackSequence import com.tunjid.treenav.switch -import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertTrue class StackNavExtTest { @@ -47,11 +40,13 @@ class StackNavExtTest { .push(TestNode("E", children = listOf(TestNode("1"), TestNode("2")))) .push(TestNode("F")) - println(pushed.backStack( - includeCurrentDestinationChildren = true, - placeChildrenBeforeParent = true, - distinctDestinations = true, - )) + println( + pushed.backStack( + includeCurrentDestinationChildren = true, + placeChildrenBeforeParent = true, + distinctDestinations = true, + ) + ) assertEquals( expected = pushed.backStack( includeCurrentDestinationChildren = true, diff --git a/library/compose/src/main/res/values/AndroidManifest.xml b/library/compose/src/main/res/values/AndroidManifest.xml index 1ac8415..6f5b391 100644 --- a/library/compose/src/main/res/values/AndroidManifest.xml +++ b/library/compose/src/main/res/values/AndroidManifest.xml @@ -14,5 +14,4 @@ ~ limitations under the License. --> - - \ No newline at end of file + \ No newline at end of file diff --git a/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/RouteDelegate.kt b/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/RouteDelegate.kt index 5e6bb1a..ec16769 100644 --- a/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/RouteDelegate.kt +++ b/library/strings/src/commonMain/kotlin/com/tunjid/treenav/strings/RouteDelegate.kt @@ -36,7 +36,7 @@ private class RouteDelegate( null -> when { isOptional -> default else -> default ?: throw NoSuchElementException( - "There is no value for the property '${property.name}' in the Route's ${if(isPath) "path arguments" else "query parameters"}." + "There is no value for the property '${property.name}' in the Route's ${if (isPath) "path arguments" else "query parameters"}." ) } diff --git a/library/treenav/src/commonMain/kotlin/com/tunjid/treenav/StackNav.kt b/library/treenav/src/commonMain/kotlin/com/tunjid/treenav/StackNav.kt index 2434ab9..8a37119 100644 --- a/library/treenav/src/commonMain/kotlin/com/tunjid/treenav/StackNav.kt +++ b/library/treenav/src/commonMain/kotlin/com/tunjid/treenav/StackNav.kt @@ -122,7 +122,7 @@ val StackNav.canPop: Boolean get() = children.size > 1 val StackNav.current: Node? get() = children.lastOrNull() -inline fun StackNav.requireCurrent(): T { +inline fun StackNav.requireCurrent(): T { val node = current ?: throw IllegalArgumentException("The current node is null") check(node is T) { "Expected the current node to be of type ${T::class.simpleName} but was ${node::class.simpleName}." diff --git a/library/treenav/src/commonTest/kotlin/MultiStackNavTest.kt b/library/treenav/src/commonTest/kotlin/MultiStackNavTest.kt index 6322686..5430858 100644 --- a/library/treenav/src/commonTest/kotlin/MultiStackNavTest.kt +++ b/library/treenav/src/commonTest/kotlin/MultiStackNavTest.kt @@ -18,12 +18,12 @@ import com.tunjid.treenav.MultiStackNav import com.tunjid.treenav.Order import com.tunjid.treenav.StackNav import com.tunjid.treenav.backStack -import com.tunjid.treenav.reversedBackStackSequence import com.tunjid.treenav.flatten import com.tunjid.treenav.minus import com.tunjid.treenav.pop import com.tunjid.treenav.popToRoot import com.tunjid.treenav.push +import com.tunjid.treenav.reversedBackStackSequence import com.tunjid.treenav.swap import com.tunjid.treenav.switch import kotlin.test.BeforeTest diff --git a/library/treenav/src/commonTest/kotlin/StackNavTest.kt b/library/treenav/src/commonTest/kotlin/StackNavTest.kt index a0527f9..8fb7628 100644 --- a/library/treenav/src/commonTest/kotlin/StackNavTest.kt +++ b/library/treenav/src/commonTest/kotlin/StackNavTest.kt @@ -18,13 +18,13 @@ import com.tunjid.treenav.Node import com.tunjid.treenav.Order import com.tunjid.treenav.StackNav import com.tunjid.treenav.backStack -import com.tunjid.treenav.reversedBackStackSequence import com.tunjid.treenav.current import com.tunjid.treenav.flatten import com.tunjid.treenav.minus import com.tunjid.treenav.pop import com.tunjid.treenav.popToRoot import com.tunjid.treenav.push +import com.tunjid.treenav.reversedBackStackSequence import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals diff --git a/libraryVersion.properties b/libraryVersion.properties index e89f8ed..ae8a36e 100644 --- a/libraryVersion.properties +++ b/libraryVersion.properties @@ -14,7 +14,7 @@ # limitations under the License. # groupId=com.tunjid.treenav -treenav_version=0.0.26 -strings_version=0.0.26 -compose_version=0.0.26 -compose-threepane_version=0.0.26 \ No newline at end of file +treenav_version=0.0.27 +strings_version=0.0.27 +compose_version=0.0.27 +compose-threepane_version=0.0.27 \ No newline at end of file diff --git a/sample/common/src/commonMain/kotlin/com/tunjid/demo/common/ui/DragToPop.kt b/sample/common/src/commonMain/kotlin/com/tunjid/demo/common/ui/DragToPop.kt index c0b2783..a63ce01 100644 --- a/sample/common/src/commonMain/kotlin/com/tunjid/demo/common/ui/DragToPop.kt +++ b/sample/common/src/commonMain/kotlin/com/tunjid/demo/common/ui/DragToPop.kt @@ -36,7 +36,6 @@ import com.tunjid.composables.dragtodismiss.dragToDismiss import com.tunjid.demo.common.ui.data.SampleDestination import com.tunjid.treenav.compose.MultiPaneDisplayScope import com.tunjid.treenav.compose.threepane.ThreePane -import com.tunjid.treenav.strings.Route @Stable internal class DragToPopState { diff --git a/sample/common/src/commonMain/kotlin/com/tunjid/demo/common/ui/PaneScaffold.kt b/sample/common/src/commonMain/kotlin/com/tunjid/demo/common/ui/PaneScaffold.kt index 373904f..f9dfc7a 100644 --- a/sample/common/src/commonMain/kotlin/com/tunjid/demo/common/ui/PaneScaffold.kt +++ b/sample/common/src/commonMain/kotlin/com/tunjid/demo/common/ui/PaneScaffold.kt @@ -51,8 +51,8 @@ import androidx.compose.ui.zIndex import com.tunjid.composables.ui.skipIf import com.tunjid.demo.common.ui.data.SampleDestination import com.tunjid.treenav.compose.PaneScope -import com.tunjid.treenav.compose.threepane.ThreePaneMovableElementSharedTransitionScope import com.tunjid.treenav.compose.threepane.ThreePane +import com.tunjid.treenav.compose.threepane.ThreePaneMovableElementSharedTransitionScope import com.tunjid.treenav.compose.threepane.rememberThreePaneMovableElementSharedTransitionScope import kotlinx.coroutines.flow.filterNot import kotlinx.coroutines.flow.filterNotNull @@ -104,7 +104,8 @@ class PaneScaffoldState internal constructor( @Composable fun PaneScope.rememberPaneScaffoldState(): PaneScaffoldState { val appState = LocalAppState.current - val paneMovableElementSharedTransitionScope = rememberThreePaneMovableElementSharedTransitionScope() + val paneMovableElementSharedTransitionScope = + rememberThreePaneMovableElementSharedTransitionScope() return remember(appState) { PaneScaffoldState( appState = appState, diff --git a/sample/common/src/commonMain/kotlin/com/tunjid/demo/common/ui/avatar/AvatarScreen.kt b/sample/common/src/commonMain/kotlin/com/tunjid/demo/common/ui/avatar/AvatarScreen.kt index f6d9078..9a8bab2 100644 --- a/sample/common/src/commonMain/kotlin/com/tunjid/demo/common/ui/avatar/AvatarScreen.kt +++ b/sample/common/src/commonMain/kotlin/com/tunjid/demo/common/ui/avatar/AvatarScreen.kt @@ -27,8 +27,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.ContentScale import com.tunjid.demo.common.ui.ProfilePhoto import com.tunjid.demo.common.ui.ProfilePhotoArgs -import com.tunjid.demo.common.ui.avatar.Action -import com.tunjid.demo.common.ui.avatar.State import com.tunjid.demo.common.ui.dragToPop import com.tunjid.treenav.compose.moveablesharedelement.MovableSharedElementScope import com.tunjid.treenav.compose.moveablesharedelement.updatedMovableSharedElementOf diff --git a/sample/common/src/iosMain/kotlin/main.ios.kt b/sample/common/src/iosMain/kotlin/main.ios.kt index 52228e6..d33cf2d 100644 --- a/sample/common/src/iosMain/kotlin/main.ios.kt +++ b/sample/common/src/iosMain/kotlin/main.ios.kt @@ -1,6 +1,6 @@ import androidx.compose.ui.window.ComposeUIViewController -import com.tunjid.demo.common.ui.AppTheme import com.tunjid.demo.common.ui.App +import com.tunjid.demo.common.ui.AppTheme fun MainViewController() = ComposeUIViewController { AppTheme { diff --git a/sample/desktop/src/jvmMain/kotlin/com/tunjid/demo/Main.kt b/sample/desktop/src/jvmMain/kotlin/com/tunjid/demo/Main.kt index ab8762a..646527a 100644 --- a/sample/desktop/src/jvmMain/kotlin/com/tunjid/demo/Main.kt +++ b/sample/desktop/src/jvmMain/kotlin/com/tunjid/demo/Main.kt @@ -21,8 +21,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Window import androidx.compose.ui.window.application import androidx.compose.ui.window.rememberWindowState -import com.tunjid.demo.common.ui.AppTheme import com.tunjid.demo.common.ui.App +import com.tunjid.demo.common.ui.AppTheme fun main() { application {