From 7e7bb175cdd0f8b0b7e0e71f33d19b1e660b06c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20Braun?= Date: Mon, 30 Sep 2024 14:01:51 +0200 Subject: [PATCH 1/2] Use Compose typed navigation --- .../kotlin/com/jetbrains/kmpapp/App.kt | 24 ++++++++++++------- .../kotlin/com/jetbrains/kmpapp/di/Koin.kt | 1 - .../kmpapp/screens/detail/DetailScreen.kt | 9 ++++--- .../kmpapp/screens/list/ListScreen.kt | 19 +++++++++------ gradle/libs.versions.toml | 4 ++-- 5 files changed, 35 insertions(+), 22 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/App.kt b/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/App.kt index 96533f4..02fa91e 100644 --- a/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/App.kt +++ b/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/App.kt @@ -10,7 +10,10 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController +import androidx.navigation.toRoute +import com.jetbrains.kmpapp.screens.detail.DetailDestination import com.jetbrains.kmpapp.screens.detail.DetailScreen +import com.jetbrains.kmpapp.screens.list.ListDestination import com.jetbrains.kmpapp.screens.list.ListScreen @Composable @@ -20,16 +23,19 @@ fun App() { ) { Surface { val navController: NavHostController = rememberNavController() - NavHost( - navController, - startDestination = "list" - ) { - composable("list") { - ListScreen(navController) + NavHost(navController = navController, startDestination = ListDestination) { + composable { + ListScreen(navigateToDetails = { objectId -> + navController.navigate(DetailDestination(objectId)) + }) } - composable("detail/{objectId}") { backStackEntry -> - val objectId = backStackEntry.arguments?.getString("objectId")?.toInt() - DetailScreen(navController, objectId!!) + composable { backStackEntry -> + DetailScreen( + objectId = backStackEntry.toRoute().objectId, + navigateBack = { + navController.popBackStack() + } + ) } } } diff --git a/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/di/Koin.kt b/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/di/Koin.kt index ee23682..6e4730c 100644 --- a/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/di/Koin.kt +++ b/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/di/Koin.kt @@ -12,7 +12,6 @@ import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.http.ContentType import io.ktor.serialization.kotlinx.json.json import kotlinx.serialization.json.Json -import org.koin.compose.viewmodel.dsl.viewModel import org.koin.core.context.startKoin import org.koin.core.module.dsl.factoryOf import org.koin.dsl.module diff --git a/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/screens/detail/DetailScreen.kt b/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/screens/detail/DetailScreen.kt index 885c5f9..b811b6b 100644 --- a/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/screens/detail/DetailScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/screens/detail/DetailScreen.kt @@ -33,7 +33,6 @@ import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp -import androidx.navigation.NavController import com.jetbrains.kmpapp.data.MuseumObject import com.jetbrains.kmpapp.screens.EmptyScreenContent import io.kamel.image.KamelImage @@ -48,20 +47,24 @@ import kmp_app_template.composeapp.generated.resources.label_dimensions import kmp_app_template.composeapp.generated.resources.label_medium import kmp_app_template.composeapp.generated.resources.label_repository import kmp_app_template.composeapp.generated.resources.label_title +import kotlinx.serialization.Serializable import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel +@Serializable +data class DetailDestination(val objectId: Int) + @Composable fun DetailScreen( - navController: NavController, objectId: Int, + navigateBack: () -> Unit, ) { val viewModel = koinViewModel() val obj by viewModel.getObject(objectId).collectAsState(initial = null) AnimatedContent(obj != null) { objectAvailable -> if (objectAvailable) { - ObjectDetails(obj!!, onBackClick = { navController.navigateUp() }) + ObjectDetails(obj!!, onBackClick = navigateBack) } else { EmptyScreenContent(Modifier.fillMaxSize()) } diff --git a/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/screens/list/ListScreen.kt b/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/screens/list/ListScreen.kt index 90767a1..58c8dbd 100644 --- a/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/screens/list/ListScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/screens/list/ListScreen.kt @@ -28,16 +28,19 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import androidx.navigation.NavController import com.jetbrains.kmpapp.data.MuseumObject import com.jetbrains.kmpapp.screens.EmptyScreenContent import io.kamel.image.KamelImage import io.kamel.image.asyncPainterResource +import kotlinx.serialization.Serializable import org.koin.compose.viewmodel.koinViewModel +@Serializable +object ListDestination + @Composable fun ListScreen( - navController: NavController, + navigateToDetails: (objectId: Int) -> Unit ) { val viewModel = koinViewModel() val objects by viewModel.objects.collectAsState() @@ -46,9 +49,7 @@ fun ListScreen( if (objectsAvailable) { ObjectGrid( objects = objects, - onObjectClick = { objectId -> - navController.navigate("detail/$objectId") - } + onObjectClick = navigateToDetails, ) } else { EmptyScreenContent(Modifier.fillMaxSize()) @@ -68,7 +69,8 @@ private fun ObjectGrid( modifier = modifier .fillMaxSize() .padding(WindowInsets.safeDrawing.only(WindowInsetsSides.Horizontal).asPaddingValues()), - contentPadding = WindowInsets.safeDrawing.only(WindowInsetsSides.Vertical).asPaddingValues(), + contentPadding = WindowInsets.safeDrawing.only(WindowInsetsSides.Vertical) + .asPaddingValues(), ) { items(objects, key = { it.objectID }) { obj -> ObjectFrame( @@ -102,7 +104,10 @@ private fun ObjectFrame( Spacer(Modifier.height(2.dp)) - Text(obj.title, style = MaterialTheme.typography.subtitle1.copy(fontWeight = FontWeight.Bold)) + Text( + obj.title, + style = MaterialTheme.typography.subtitle1.copy(fontWeight = FontWeight.Bold) + ) Text(obj.artistDisplayName, style = MaterialTheme.typography.body2) Text(obj.objectDate, style = MaterialTheme.typography.caption) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5ea2418..0344b46 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,13 +1,13 @@ [versions] agp = "8.6.0" androidx-activityCompose = "1.9.2" -androidx-ui-tooling = "1.7.0" +androidx-ui-tooling = "1.7.2" compose-multiplatform = "1.6.11" kamel = "0.9.5" koin = "4.0.0" kotlin = "2.0.20" ktor = "2.3.12" -navigationCompose = "2.7.0-alpha07" +navigationCompose = "2.8.0-alpha10" [libraries] androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" } From 8b1aa9a8d920546e6fa6ccdb43881fe40865944f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rton=20Braun?= Date: Mon, 30 Sep 2024 14:03:31 +0200 Subject: [PATCH 2/2] Move destination objects to App.kt --- .../src/commonMain/kotlin/com/jetbrains/kmpapp/App.kt | 9 +++++++-- .../com/jetbrains/kmpapp/screens/detail/DetailScreen.kt | 4 ---- .../com/jetbrains/kmpapp/screens/list/ListScreen.kt | 4 ---- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/App.kt b/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/App.kt index 02fa91e..288ff74 100644 --- a/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/App.kt +++ b/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/App.kt @@ -11,10 +11,15 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.navigation.toRoute -import com.jetbrains.kmpapp.screens.detail.DetailDestination import com.jetbrains.kmpapp.screens.detail.DetailScreen -import com.jetbrains.kmpapp.screens.list.ListDestination import com.jetbrains.kmpapp.screens.list.ListScreen +import kotlinx.serialization.Serializable + +@Serializable +object ListDestination + +@Serializable +data class DetailDestination(val objectId: Int) @Composable fun App() { diff --git a/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/screens/detail/DetailScreen.kt b/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/screens/detail/DetailScreen.kt index b811b6b..0fb88a7 100644 --- a/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/screens/detail/DetailScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/screens/detail/DetailScreen.kt @@ -47,13 +47,9 @@ import kmp_app_template.composeapp.generated.resources.label_dimensions import kmp_app_template.composeapp.generated.resources.label_medium import kmp_app_template.composeapp.generated.resources.label_repository import kmp_app_template.composeapp.generated.resources.label_title -import kotlinx.serialization.Serializable import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel -@Serializable -data class DetailDestination(val objectId: Int) - @Composable fun DetailScreen( objectId: Int, diff --git a/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/screens/list/ListScreen.kt b/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/screens/list/ListScreen.kt index 58c8dbd..4ed0d4f 100644 --- a/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/screens/list/ListScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/jetbrains/kmpapp/screens/list/ListScreen.kt @@ -32,12 +32,8 @@ import com.jetbrains.kmpapp.data.MuseumObject import com.jetbrains.kmpapp.screens.EmptyScreenContent import io.kamel.image.KamelImage import io.kamel.image.asyncPainterResource -import kotlinx.serialization.Serializable import org.koin.compose.viewmodel.koinViewModel -@Serializable -object ListDestination - @Composable fun ListScreen( navigateToDetails: (objectId: Int) -> Unit