diff --git a/sample/app-desktop/saved_state.dat b/sample/app-desktop/saved_state.dat deleted file mode 100644 index 4f6acd3f1..000000000 --- a/sample/app-desktop/saved_state.dat +++ /dev/null @@ -1 +0,0 @@ -true[80,75,3,4,20,0,8,8,8,0,-106,-106,-124,87,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-115,89,-53,-82,54,71,13,124,-105,127,-35,-97,-44,-9,118,103,11,111,-64,18,-79,-120,32,8,68,-112,16,74,86,81,-34,-99,-70,-72,15,-53,68,71,-25,54,-33,76,-73,-37,46,-105,-53,-98,95,-66,-3,-5,-5,-1,124,-5,-18,-105,111,127,-4,-31,-17,-33,-1,-4,-29,79,127,-8,-57,63,127,-4,-37,-97,126,-6,-2,-81,-1,-6,-10,-35,79,-1,-3,-7,-121,63,71,45,103,-107,81,102,-23,-75,-44,18,-6,-86,-27,-45,-22,126,63,-6,44,113,74,-3,-115,-81,79,-116,18,81,62,107,-31,-111,-122,-27,110,-39,-73,52,44,48,-71,-48,42,-21,112,25,108,-10,-63,-9,60,-68,-66,-53,105,120,98,-108,83,90,43,-109,55,-10,-29,29,23,30,-68,-37,23,-16,-39,103,96,-121,49,-72,-12,45,3,-105,-86,-18,-21,-72,120,-68,-19,46,-99,-73,55,-36,-45,-79,-57,-26,-25,-72,-50,91,98,-106,-37,-53,-104,101,-32,-125,-117,27,120,-29,-79,85,90,116,47,91,-119,125,96,-10,-89,-73,-4,108,-30,-113,104,52,118,-13,46,46,-121,79,-106,119,-64,-121,-25,-106,-123,-5,3,-65,112,-8,-50,-61,109,60,50,105,103,-83,-123,110,-8,-116,-48,126,116,75,-121,-101,91,105,92,126,112,-69,66,-1,98,-115,-122,15,62,-73,-55,6,108,-60,43,-43,-73,99,31,108,-64,53,-49,-47,-123,-53,-19,-114,118,-91,39,91,-59,-90,-45,15,-29,-79,-49,-64,-9,92,122,28,-117,-64,85,-76,-10,-30,-47,-47,-54,112,-116,94,100,113,113,-51,114,112,97,-34,114,-62,-114,-63,58,56,12,-17,-54,-115,-20,-48,-125,39,14,30,-9,-22,-97,85,-27,-14,-127,-85,3,14,-103,53,55,-121,-79,-80,101,110,45,-128,-115,27,62,-68,-95,-29,33,12,75,56,64,100,-101,87,111,-107,123,119,-102,48,4,-115,79,116,-57,101,58,66,-67,32,-128,116,33,-10,-36,90,-119,-47,92,60,-104,-41,-1,-20,94,120,21,6,0,92,-118,79,-85,77,-121,-107,81,51,20,37,29,72,62,-90,-21,25,73,-128,30,62,-43,50,52,-107,127,-45,-45,8,-58,-79,31,112,-125,-10,96,24,-80,3,-80,53,28,2,64,9,31,-36,41,0,-45,102,120,-11,46,62,71,48,2,-73,48,107,-31,24,43,116,-94,-87,115,-60,-125,-85,66,97,7,-45,36,58,-128,14,108,-119,-11,97,-100,-97,-82,120,96,-91,-67,-71,21,79,58,51,17,63,27,-1,-41,-103,-1,32,114,-80,-50,-120,111,-83,26,-80,120,108,17,-119,10,-5,48,26,67,27,32,96,-93,25,52,-97,101,32,12,-70,-95,-55,125,-40,66,-117,6,113,89,51,109,-19,55,29,101,38,-12,101,-125,50,-128,-15,-51,-8,-48,29,-37,-97,-14,-95,-74,124,-18,79,-9,-57,31,-109,1,83,-71,-105,121,-19,54,31,30,127,-31,-63,-95,-36,37,93,-64,100,-60,-114,48,-120,101,32,-47,-85,34,7,-26,114,-21,53,79,64,43,114,1,-63,89,-103,-34,-103,-29,-12,6,76,10,7,-4,-61,-61,29,-93,90,-103,-115,21,-112,65,75,-112,102,-54,55,110,-74,70,-82,56,125,-44,109,22,-29,103,67,126,69,106,-47,-24,-31,91,101,6,-96,36,80,-13,-96,-118,99,-85,-119,-64,67,15,-9,36,-128,33,47,-119,19,-101,124,-72,76,15,8,-112,-48,55,-124,-71,-105,-126,90,-7,122,85,56,-128,-103,87,-80,-72,55,-60,39,111,11,-90,-4,-18,114,53,-64,118,-101,-61,65,63,-110,46,86,-92,93,36,-9,120,116,68,24,43,41,-105,-17,32,68,0,48,-78,73,-125,-21,91,37,-111,-106,-39,5,2,110,72,110,-127,31,91,25,25,125,58,116,102,-28,-108,29,60,86,-94,26,92,-114,-53,-111,11,116,114,29,45,36,-4,-103,76,-128,26,-16,-52,104,-19,109,-92,2,18,-60,53,-79,-45,-108,67,-5,-40,-68,109,4,50,-114,-125,-26,59,15,113,2,96,-91,-109,31,69,75,92,-12,10,81,68,6,-47,19,-118,-113,48,54,-103,57,-76,10,-98,1,49,32,102,67,127,-100,-60,16,108,78,62,7,-7,-100,-28,-72,125,-45,-71,-120,122,36,-58,55,-77,-102,65,-60,90,-67,41,-51,87,-107,-93,-5,-52,20,-48,15,-4,71,-4,-84,-109,105,-45,21,-120,-83,-59,-123,50,-8,1,75,16,22,-16,18,106,-107,2,122,76,-84,96,-22,-57,112,-84,-63,-68,54,-24,-124,78,127,-119,-24,-79,-34,-42,1,104,10,29,-114,-70,72,-74,94,-114,57,99,2,110,-30,-18,12,55,-7,107,17,-78,-82,-119,-21,101,66,19,24,-128,56,-62,104,-114,87,-86,-82,106,-117,17,-37,31,-124,-99,15,-28,-28,32,56,85,-41,-85,-127,2,67,1,-4,-21,101,98,-66,-78,-53,106,-71,-67,12,-77,-122,-48,32,15,86,-63,-128,76,-117,68,-65,118,-75,-16,-54,-27,-56,-82,-124,15,-10,-64,-127,-123,-4,110,32,-120,50,-103,-102,55,-20,94,74,3,-63,-65,63,50,-44,15,46,-123,-57,-79,107,84,63,-47,-78,-64,93,34,99,11,-121,58,-110,-62,-53,-78,-126,108,-85,46,64,12,-114,-128,94,-67,54,126,3,-67,65,50,-127,107,-71,0,-63,44,38,51,-5,3,-80,-41,-27,-114,37,-125,-18,81,104,-90,104,20,-111,-64,-19,-103,107,-14,-44,86,-11,-25,9,-82,28,-23,64,-122,-24,12,-68,-56,-83,87,119,-83,-125,-123,-16,22,117,-49,-82,37,115,-85,25,121,67,-105,89,115,-37,-76,4,-46,-7,72,-32,-47,116,-1,56,-103,-84,-125,81,-73,-68,96,-103,-48,-39,36,-77,-32,-8,-19,108,25,75,-101,109,123,-60,-123,113,-101,12,-32,-63,44,-2,-44,78,109,91,-81,-8,112,-63,26,35,56,-123,124,-59,-46,125,-100,76,-4,88,-58,30,-7,-32,35,-20,78,71,-104,-104,103,20,97,-95,116,-52,-54,-88,-14,7,124,-63,-76,91,38,76,66,20,30,102,101,12,47,-121,103,-25,81,101,107,89,111,64,70,48,78,44,7,-98,25,-14,19,85,29,87,-22,46,53,-8,-109,-59,-97,-15,34,102,-31,53,50,-120,-31,-3,60,18,-90,98,29,-78,37,-103,-98,109,-97,-119,108,-23,87,-27,48,-111,77,92,81,39,23,62,32,92,34,-125,-56,92,97,59,20,25,-42,-41,-93,68,-31,50,-95,77,-120,29,25,-7,-40,-104,-52,-73,12,113,-127,-9,100,25,-106,112,3,97,-123,28,-62,-112,40,7,12,112,-20,50,-83,-58,-122,-123,2,78,41,-127,-96,101,107,50,51,-18,66,78,98,-109,-99,-82,20,106,-73,28,76,6,112,109,114,-51,-108,-34,-20,41,7,17,-121,-69,-77,114,-124,-24,-125,57,-65,-21,-85,53,35,-59,107,56,-114,-40,-57,-12,60,76,-17,-29,125,-42,-98,98,20,-127,-122,75,-41,-74,59,-102,-42,52,-71,0,-62,60,-114,-128,110,-114,-93,45,112,-43,86,-67,-65,-118,18,-93,-126,-65,-114,-108,0,17,-90,-37,26,121,67,-121,32,-86,36,124,-81,-50,107,-118,-84,-114,72,-62,75,42,106,-24,115,62,77,-5,102,106,64,85,-11,-31,-53,-14,-66,36,40,-110,-122,-54,-106,59,112,117,85,12,-98,104,-41,68,116,-93,-90,-69,41,-118,17,-62,78,-91,33,71,-54,-68,-108,38,44,-105,31,-47,64,112,-61,19,18,122,74,-111,-6,122,-117,106,2,-28,83,-39,43,-80,36,-103,-72,-7,40,-13,-20,-12,-30,-109,84,91,-126,4,94,-14,28,15,124,13,125,-34,-5,118,-81,-86,16,-103,29,-90,74,-27,102,72,-54,93,-47,-27,16,99,41,-39,24,-41,43,-76,99,79,-15,5,29,3,112,75,-73,91,71,15,57,91,-53,79,-41,-3,105,-115,55,77,-13,-84,112,-89,37,45,16,4,88,28,17,48,-7,89,87,48,72,-16,106,23,49,-64,28,-102,-16,101,-118,-37,49,-36,-26,-126,76,47,-17,-102,80,26,41,46,-128,10,28,-104,-44,-99,-12,-27,122,-74,-52,37,42,-69,-21,109,44,-40,-120,61,9,27,-96,121,88,91,-15,-23,97,-15,116,-36,-80,40,27,54,-37,24,9,-65,-82,82,76,77,96,120,81,-47,-6,-124,102,-25,-44,-65,-93,63,6,-18,-114,-102,-60,-25,84,-34,54,55,34,83,25,119,-83,-18,-17,-53,57,-44,-27,-43,68,43,-95,98,15,88,-78,108,-126,-36,-124,32,-30,-100,-50,-38,110,-120,-23,85,75,101,85,72,119,-123,44,90,-57,-59,15,123,-88,99,61,69,125,-56,50,-34,-28,106,107,123,67,123,-51,108,98,-26,99,32,-89,-67,-43,115,-11,5,42,15,-73,50,34,106,37,-79,-37,105,-83,117,21,118,-58,84,-19,-125,-55,94,-115,-82,34,64,-24,84,30,-104,-51,3,-78,-122,-35,-85,-101,37,53,-122,-9,5,-21,102,-43,-58,-95,1,53,22,21,24,-60,-102,123,-110,76,-67,22,5,46,-103,-19,72,65,100,-95,-93,118,14,-3,-33,-35,60,-69,-14,-85,-121,-127,-97,-121,58,111,93,15,37,-64,-52,-67,-10,116,74,62,-109,59,65,-72,-102,-97,-59,-7,-30,-1,-84,34,40,-20,-108,-23,61,41,25,34,-71,103,43,4,-4,44,117,98,22,-97,48,49,-85,-46,44,41,80,40,9,-69,-100,65,50,-60,-22,55,-111,-92,-50,-80,38,-51,76,107,98,105,-38,-23,-6,-126,109,97,-2,117,17,-63,115,64,-54,-52,22,114,-89,-60,-34,-39,-98,-116,-84,-3,106,-12,16,14,51,-84,-39,123,-71,-41,-70,-26,14,6,53,81,83,-81,-69,58,54,27,-66,79,-98,19,-107,-47,-51,-110,-40,95,61,-107,-2,-64,-6,32,-4,-95,-22,-76,119,10,4,-57,-93,-47,-78,110,24,-77,111,-23,-105,-90,-117,-33,-86,15,12,92,69,-50,97,-114,-23,-77,-105,-52,-37,101,-95,-58,70,32,113,-51,-91,103,117,-126,73,56,-45,-10,-110,73,44,76,-57,76,18,36,20,-114,-3,-104,45,-39,81,10,93,-127,14,-89,123,77,-112,2,-14,100,10,-16,48,21,41,10,-22,16,-22,1,74,-75,-79,-82,-23,-36,80,61,-111,122,-64,-101,125,96,77,69,-112,83,21,-107,124,14,18,66,114,-117,76,71,54,96,-110,119,-49,12,68,-55,-57,-35,97,-51,1,68,-88,-93,-87,98,-123,-69,-97,38,27,-2,63,-104,49,-68,21,-98,-106,-80,-102,-10,-51,-87,111,-53,-59,-16,72,45,-121,89,104,88,-38,11,-37,-100,-128,-31,20,84,102,87,21,62,86,-10,68,-37,1,-28,-75,-111,69,113,28,-109,21,25,-120,-75,36,43,-78,-124,15,-89,41,-126,103,-45,-34,-12,0,-113,-75,-66,-38,82,85,-73,28,126,-120,7,87,-3,42,-28,-115,56,-47,-56,-92,101,-93,-80,61,-33,59,-39,78,89,-68,104,14,-61,124,104,22,60,-46,-39,18,-113,56,113,79,30,74,125,116,93,79,87,-102,-76,94,-44,43,-111,-88,121,-49,81,67,-84,-95,1,111,99,3,-50,-106,-13,9,0,38,-117,10,-123,86,39,-96,122,106,44,26,-51,97,-94,-101,42,90,-64,103,65,106,18,-66,-94,113,21,50,-2,118,-85,115,-44,115,-20,108,-87,53,60,-86,-22,-72,-70,-55,104,-67,-119,90,-77,-58,37,-17,106,70,115,77,104,47,103,-85,33,-73,95,-49,-125,-17,123,83,-112,37,1,57,-13,-99,68,95,45,14,-83,-23,57,44,96,-10,-112,110,-86,-77,46,-15,-89,64,94,23,-104,41,-31,-122,51,45,-79,-21,122,44,110,89,102,-27,-58,26,28,-98,-71,-100,-20,96,84,-47,-91,-110,-106,-121,16,45,-93,63,-51,26,-12,-121,-25,115,-102,21,-43,60,-49,21,54,1,101,38,-55,-40,57,-117,-112,-30,-15,-100,-90,-119,112,-82,-121,-62,-40,104,63,22,49,-99,52,18,119,119,41,-56,-114,-115,61,-58,-80,85,18,107,83,-108,118,-76,-79,-49,-86,-59,-122,-10,20,104,-113,-113,56,-115,-79,-72,-87,68,-86,90,113,-115,125,114,-108,-90,17,-100,27,48,-78,100,-51,105,-89,-121,-45,67,-51,35,5,31,23,91,-26,-80,-21,-39,-43,-14,-16,-58,-77,69,-75,36,46,84,-35,-29,69,81,-17,-7,26,88,-91,-14,-50,-39,-93,104,49,103,-71,87,-54,-116,57,76,6,-42,33,-72,-123,-54,-10,-11,4,18,49,-69,-116,90,54,-35,-62,-65,74,93,-51,94,-3,122,-90,-8,34,39,127,-123,-4,-87,-76,53,-37,-14,-73,6,32,75,-93,83,-16,-43,-18,-39,-55,84,-39,-69,-77,-123,-103,18,101,93,-128,-96,-119,-46,72,28,-3,51,-2,108,-61,-22,87,-111,30,55,-121,4,64,-38,-101,69,-69,120,13,77,-108,-56,-76,112,-44,116,95,-56,-114,40,68,26,-29,-119,-15,-109,53,-71,-71,-30,-45,106,42,125,-113,93,67,116,-90,-74,109,-71,62,-118,-43,-28,-102,-86,-23,54,-33,28,-72,5,-124,27,116,70,-122,95,-45,102,36,103,-54,-27,21,95,-122,124,-94,124,53,3,67,64,19,118,-98,4,-90,119,-81,103,88,-102,88,-23,61,-63,16,-111,83,-33,-121,-25,-108,-45,102,83,47,2,110,-6,-107,-91,126,57,85,7,19,102,73,-48,124,-106,-57,-65,-61,-53,117,-73,52,74,120,-62,-98,-83,111,79,55,14,-58,-32,48,-44,98,-41,112,-48,60,-103,72,-38,-116,-100,-4,-92,5,-35,122,123,-25,-102,126,-117,-95,-74,-44,51,-49,-18,-119,101,-13,-24,-102,-23,72,53,-47,50,46,-102,-52,104,-104,-17,-84,-110,96,86,-117,37,41,90,-105,-21,-85,76,13,19,110,120,60,-43,-52,-3,77,58,67,-6,-27,-75,17,-11,62,-70,-50,50,94,-77,7,-32,-24,-60,2,-46,61,94,-105,2,93,14,-54,-35,-119,-100,-6,84,-35,-107,68,20,11,101,-104,34,-25,-91,-37,-117,90,-15,40,-101,119,-122,56,-92,-64,-56,-16,-84,104,33,124,-120,81,-44,-106,-69,-88,-45,-114,-31,-9,31,106,-57,-34,-69,30,57,-124,100,-63,-66,39,-4,-86,-26,-68,-105,34,-98,75,75,28,-67,-128,-24,-120,71,-93,-126,-31,-66,-38,3,-62,36,-58,-95,33,-35,-55,-120,107,18,103,10,-49,-26,-118,-48,-52,81,-64,113,-75,-99,-42,17,43,44,15,-45,-67,-92,28,-50,-87,-106,-34,-63,105,-118,27,62,126,-10,-7,20,41,-51,-17,-123,60,92,-86,-87,-89,117,-16,-101,-19,-19,116,-90,-69,-50,-102,116,-74,111,75,78,-108,-11,43,-93,62,114,82,120,111,114,-91,102,-4,-98,72,-15,-3,-127,122,66,119,126,-95,41,-42,-108,-84,84,1,-40,-9,21,2,-127,-38,-118,89,47,-91,-44,-77,-70,114,26,16,126,89,-13,37,-52,-36,-98,100,73,-21,-98,-7,-67,17,37,78,123,93,-72,5,-27,-18,-52,56,-114,7,81,-90,78,-126,47,13,85,20,-79,49,9,-121,31,-66,65,-84,6,-55,77,61,30,-71,-110,-17,109,-84,82,35,11,47,-119,57,18,113,93,-124,117,-12,-74,100,-17,44,-17,-15,38,99,73,-82,30,-99,-98,-25,-65,105,16,-88,-21,98,-116,93,-54,104,-102,-122,21,41,29,-73,7,112,-110,113,91,-60,-96,114,-105,-17,1,-89,24,127,-24,53,23,115,50,-84,25,56,43,28,30,-108,-21,95,109,123,91,-55,-63,-125,85,-97,94,-98,-87,86,-8,-123,-27,-15,124,41,-45,74,-108,-39,-28,-99,-56,87,70,52,73,-17,4,13,-92,-105,125,43,-101,-109,-124,79,-49,-69,89,84,36,109,-8,-30,65,115,-25,55,6,-65,41,-48,-74,7,6,126,-31,-85,-105,46,126,-7,-21,-69,27,39,34,-4,-9,55,94,37,-1,-98,21,127,-49,-105,119,-27,-53,-63,119,-91,-27,-9,124,-105,78,-28,-38,-8,-6,-53,-81,-65,-2,15,80,75,7,8,15,101,-112,97,-121,12,0,0,15,31,0,0,80,75,1,2,20,0,20,0,8,8,8,0,-106,-106,-124,87,15,101,-112,97,-121,12,0,0,15,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,75,5,6,0,0,0,0,1,0,1,0,46,0,0,0,-75,12,0,0,0,0] \ No newline at end of file diff --git a/sample/app-ios/app-ios/KittenView.swift b/sample/app-ios/app-ios/KittenView.swift index a65d16aa7..367d971e3 100644 --- a/sample/app-ios/app-ios/KittenView.swift +++ b/sample/app-ios/app-ios/KittenView.swift @@ -10,7 +10,7 @@ struct KittenView: View { private var model: KittenComponentModel private var imageName: String { - switch model.imageType { + switch model.imageResourceId { case .cat1: return "cat1" case .cat2: return "cat2" case .cat3: return "cat3" @@ -77,8 +77,3 @@ struct KittenView_Previews: PreviewProvider { KittenView(PreviewKittenComponent(), .large) } } - -class PreviewKittenComponent: KittenComponent { - var model: Value = mutableValue(KittenComponentModel(imageType: .cat1, text: "000")) -} - diff --git a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/PainterResource.kt b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/PainterResource.kt new file mode 100644 index 000000000..c1e684cdc --- /dev/null +++ b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/PainterResource.kt @@ -0,0 +1,25 @@ +package com.arkivanov.sample.shared + +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.painter.Painter +import decompose.sample.shared.compose.generated.resources.Res +import decompose.sample.shared.compose.generated.resources.cat1 +import decompose.sample.shared.compose.generated.resources.cat2 +import decompose.sample.shared.compose.generated.resources.cat3 +import decompose.sample.shared.compose.generated.resources.cat4 +import decompose.sample.shared.compose.generated.resources.cat5 +import org.jetbrains.compose.resources.ExperimentalResourceApi +import org.jetbrains.compose.resources.painterResource + +@OptIn(ExperimentalResourceApi::class) +@Composable +internal fun painterResource(imageResourceId: ImageResourceId): Painter = + painterResource( + when (imageResourceId) { + ImageResourceId.CAT_1 -> Res.drawable.cat1 + ImageResourceId.CAT_2 -> Res.drawable.cat2 + ImageResourceId.CAT_3 -> Res.drawable.cat3 + ImageResourceId.CAT_4 -> Res.drawable.cat4 + ImageResourceId.CAT_5 -> Res.drawable.cat5 + } + ) diff --git a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/KittenContent.kt b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/KittenContent.kt index e3e770788..8285aa293 100644 --- a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/KittenContent.kt +++ b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/KittenContent.kt @@ -1,5 +1,6 @@ package com.arkivanov.sample.shared.customnavigation +import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box @@ -16,20 +17,12 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.arkivanov.decompose.extensions.compose.subscribeAsState -import decompose.sample.shared.compose.generated.resources.Res -import decompose.sample.shared.compose.generated.resources.cat1 -import decompose.sample.shared.compose.generated.resources.cat2 -import decompose.sample.shared.compose.generated.resources.cat3 -import decompose.sample.shared.compose.generated.resources.cat4 -import decompose.sample.shared.compose.generated.resources.cat5 -import org.jetbrains.compose.resources.ExperimentalResourceApi -import org.jetbrains.compose.resources.painterResource +import com.arkivanov.sample.shared.painterResource @Composable internal fun KittenContent( @@ -41,7 +34,7 @@ internal fun KittenContent( Box(modifier = modifier) { Image( - painter = getKittenPainter(imageType = model.imageType), + painter = painterResource(model.imageResourceId), contentDescription = "Kitten image", modifier = Modifier.fillMaxSize(), contentScale = ContentScale.Crop, @@ -63,15 +56,11 @@ internal fun KittenContent( } } -@OptIn(ExperimentalResourceApi::class) +@Preview @Composable -internal fun getKittenPainter(imageType: KittenComponent.ImageType): Painter = - painterResource( - when (imageType) { - KittenComponent.ImageType.CAT_1 -> Res.drawable.cat1 - KittenComponent.ImageType.CAT_2 -> Res.drawable.cat2 - KittenComponent.ImageType.CAT_3 -> Res.drawable.cat3 - KittenComponent.ImageType.CAT_4 -> Res.drawable.cat4 - KittenComponent.ImageType.CAT_5 -> Res.drawable.cat5 - } +internal fun KittenContentPreview() { + KittenContent( + component = PreviewKittenComponent(), + textStyle = TextStyle.Default, ) +} diff --git a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/menu/MenuContent.kt b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/menu/MenuContent.kt index a440174a7..90c7a4c5e 100644 --- a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/menu/MenuContent.kt +++ b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/menu/MenuContent.kt @@ -36,6 +36,7 @@ internal fun MenuContent( TextButton(text = "Dynamic Features", onClick = component.onDynamicFeaturesItemSelected) TextButton(text = "Custom Navigation", onClick = component.onCustomNavigationItemSelected) TextButton(text = "Pages", onClick = component.onPagesItemSelected) + TextButton(text = "Shared Transitions", onClick = component.onSharedTransitionsItemSelected) } } } diff --git a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/pages/PagesContent.kt b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/pages/PagesContent.kt index db1c46a82..6eeb937f0 100644 --- a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/pages/PagesContent.kt +++ b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/pages/PagesContent.kt @@ -11,28 +11,24 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.material.Icon -import androidx.compose.material.IconButton -import androidx.compose.material.LocalContentColor import androidx.compose.material.MaterialTheme import androidx.compose.material.OutlinedButton import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowForward -import androidx.compose.material.icons.filled.Close import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import com.arkivanov.decompose.ExperimentalDecomposeApi import com.arkivanov.decompose.extensions.compose.pages.Pages import com.arkivanov.decompose.extensions.compose.pages.PagesScrollAnimation import com.arkivanov.sample.shared.customnavigation.KittenContent +import com.arkivanov.sample.shared.utils.CloseButton @OptIn(ExperimentalFoundationApi::class, ExperimentalDecomposeApi::class) @Composable -fun PagesContent(component: PagesComponent, modifier: Modifier = Modifier) { +internal fun PagesContent(component: PagesComponent, modifier: Modifier = Modifier) { Box(modifier = modifier) { Pages( pages = component.pages, @@ -47,20 +43,10 @@ fun PagesContent(component: PagesComponent, modifier: Modifier = Modifier) { ) } - CompositionLocalProvider(LocalContentColor provides Color.White) { - IconButton( - onClick = component::onCloseClicked, - modifier = Modifier - .align(Alignment.TopStart) - .statusBarsPadding() - .padding(4.dp), - ) { - Icon( - imageVector = Icons.Default.Close, - contentDescription = "Close button", - ) - } - } + CloseButton( + onClick = component::onCloseClicked, + modifier = Modifier.align(Alignment.TopStart).statusBarsPadding(), + ) Row( modifier = Modifier.align(Alignment.BottomCenter).padding(bottom = 16.dp).navigationBarsPadding(), diff --git a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/root/RootContent.kt b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/root/RootContent.kt index 4f075d7db..a9a3d6f45 100644 --- a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/root/RootContent.kt +++ b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/root/RootContent.kt @@ -19,7 +19,9 @@ import com.arkivanov.sample.shared.pages.PagesContent import com.arkivanov.sample.shared.root.RootComponent.Child.CustomNavigationChild import com.arkivanov.sample.shared.root.RootComponent.Child.DynamicFeaturesChild import com.arkivanov.sample.shared.root.RootComponent.Child.PagesChild +import com.arkivanov.sample.shared.root.RootComponent.Child.SharedTransitionsChild import com.arkivanov.sample.shared.root.RootComponent.Child.TabsChild +import com.arkivanov.sample.shared.sharedtransitions.SharedTransitionsContent import com.arkivanov.sample.shared.tabs.TabsContent @Composable @@ -50,6 +52,7 @@ private fun Children(component: RootComponent, modifier: Modifier = Modifier) { is DynamicFeaturesChild -> DynamicFeaturesContent(component = child.component, modifier = Modifier.fillMaxSize()) is CustomNavigationChild -> CustomNavigationContent(component = child.component, modifier = Modifier.fillMaxSize()) is PagesChild -> PagesContent(component = child.component, modifier = Modifier.fillMaxSize()) + is SharedTransitionsChild -> SharedTransitionsContent(component = child.component, modifier = Modifier.fillMaxSize()) } } } diff --git a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/SharedTransitionsContent.kt b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/SharedTransitionsContent.kt new file mode 100644 index 000000000..2a1a6c2f9 --- /dev/null +++ b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/SharedTransitionsContent.kt @@ -0,0 +1,53 @@ +package com.arkivanov.sample.shared.sharedtransitions + +import androidx.compose.animation.ExperimentalSharedTransitionApi +import androidx.compose.animation.SharedTransitionLayout +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import com.arkivanov.decompose.extensions.compose.stack.Children +import com.arkivanov.decompose.extensions.compose.stack.animation.fade +import com.arkivanov.decompose.extensions.compose.stack.animation.plus +import com.arkivanov.decompose.extensions.compose.stack.animation.scale +import com.arkivanov.decompose.extensions.compose.stack.animation.stackAnimation +import com.arkivanov.decompose.extensions.compose.subscribeAsState +import com.arkivanov.sample.shared.sharedtransitions.SharedTransitionsComponent.Child.GalleryChild +import com.arkivanov.sample.shared.sharedtransitions.SharedTransitionsComponent.Child.PhotoChild +import com.arkivanov.sample.shared.sharedtransitions.gallery.GalleryContent +import com.arkivanov.sample.shared.sharedtransitions.photo.PhotoContent + +@OptIn(ExperimentalSharedTransitionApi::class) +@Composable +internal fun SharedTransitionsContent( + component: SharedTransitionsComponent, + modifier: Modifier = Modifier, +) { + val stack by component.stack.subscribeAsState() + + SharedTransitionLayout(modifier = modifier) { + Children( + stack = component.stack, + modifier = Modifier.fillMaxSize().background(Color.Black), + animation = stackAnimation(fade() + scale()), + ) { + when (val child = it.instance) { + is GalleryChild -> + GalleryContent( + component = child.component, + isVisible = stack.active.instance is GalleryChild, + modifier = Modifier.fillMaxSize(), + ) + + is PhotoChild -> + PhotoContent( + component = child.component, + isVisible = stack.active.instance is PhotoChild, + modifier = Modifier.fillMaxSize(), + ) + } + } + } +} diff --git a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/gallery/GalleryContent.kt b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/gallery/GalleryContent.kt new file mode 100644 index 000000000..6ac70130b --- /dev/null +++ b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/gallery/GalleryContent.kt @@ -0,0 +1,66 @@ +package com.arkivanov.sample.shared.sharedtransitions.gallery + +import androidx.compose.animation.ExperimentalSharedTransitionApi +import androidx.compose.animation.SharedTransitionLayout +import androidx.compose.animation.SharedTransitionScope +import androidx.compose.desktop.ui.tooling.preview.Preview +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.itemsIndexed +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.unit.dp +import com.arkivanov.sample.shared.painterResource +import com.arkivanov.sample.shared.utils.TopAppBar + +@OptIn(ExperimentalSharedTransitionApi::class) +@Composable +internal fun SharedTransitionScope.GalleryContent( + component: GalleryComponent, + isVisible: Boolean, + modifier: Modifier = Modifier, +) { + Column(modifier = modifier) { + TopAppBar(title = "Photo Gallery", onCloseClick = component::onCloseClicked) + + LazyVerticalGrid( + columns = GridCells.Adaptive(minSize = 128.dp), + modifier = Modifier.fillMaxWidth().weight(1F), + ) { + itemsIndexed(items = component.images) { index, image -> + Image( + painter = painterResource(image.resourceId), + contentDescription = null, + modifier = Modifier + .aspectRatio(1F) + .sharedElementWithCallerManagedVisibility( + sharedContentState = rememberSharedContentState(key = image.id), + visible = isVisible, + ) + .clickable { component.onImageClicked(index = index) }, + contentScale = ContentScale.Crop, + ) + } + } + } +} + +@OptIn(ExperimentalSharedTransitionApi::class) +@Preview +@Composable +internal fun GalleryContentPreview() { + SharedTransitionLayout { + GalleryContent( + component = PreviewGalleryComponent(), + isVisible = true, + modifier = Modifier.fillMaxSize(), + ) + } +} diff --git a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/photo/PhotoContent.kt b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/photo/PhotoContent.kt new file mode 100644 index 000000000..f498ee93c --- /dev/null +++ b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/photo/PhotoContent.kt @@ -0,0 +1,56 @@ +package com.arkivanov.sample.shared.sharedtransitions.photo + +import androidx.compose.animation.ExperimentalSharedTransitionApi +import androidx.compose.animation.SharedTransitionLayout +import androidx.compose.animation.SharedTransitionScope +import androidx.compose.desktop.ui.tooling.preview.Preview +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import com.arkivanov.sample.shared.painterResource +import com.arkivanov.sample.shared.utils.TopAppBar + +@OptIn(ExperimentalSharedTransitionApi::class) +@Composable +internal fun SharedTransitionScope.PhotoContent( + component: PhotoComponent, + isVisible: Boolean, + modifier: Modifier = Modifier, +) { + Column(modifier = modifier) { + TopAppBar(title = "Photo ${component.image.id}", onCloseClick = component::onCloseClicked) + + Image( + painter = painterResource(component.image.resourceId), + contentDescription = null, + modifier = Modifier + .sharedElementWithCallerManagedVisibility( + sharedContentState = rememberSharedContentState(key = component.image.id), + visible = isVisible, + ) + .fillMaxWidth() + .weight(1F) + .background(Color.Black), + contentScale = ContentScale.Crop, + ) + } +} + +@OptIn(ExperimentalSharedTransitionApi::class) +@Preview +@Composable +internal fun PhotoContentPreview() { + SharedTransitionLayout { + PhotoContent( + component = PreviewPhotoComponent(), + isVisible = true, + modifier = Modifier.fillMaxSize(), + ) + } +} diff --git a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/utils/Views.kt b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/utils/Views.kt index cd0eed8f5..a42db5d05 100644 --- a/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/utils/Views.kt +++ b/sample/shared/compose/src/commonMain/kotlin/com/arkivanov/sample/shared/utils/Views.kt @@ -1,17 +1,22 @@ package com.arkivanov.sample.shared.utils import androidx.compose.foundation.background +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.material.Icon import androidx.compose.material.IconButton +import androidx.compose.material.LocalContentColor import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.TopAppBar import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.Close import androidx.compose.material.primarySurface import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp @Composable @@ -35,3 +40,21 @@ internal fun TopAppBar( elevation = 0.dp, ) } + +@Composable +internal fun CloseButton( + modifier: Modifier = Modifier, + onClick: () -> Unit = {}, +) { + CompositionLocalProvider(LocalContentColor provides Color.White) { + IconButton( + onClick = onClick, + modifier = modifier.padding(4.dp), + ) { + Icon( + imageVector = Icons.Default.Close, + contentDescription = "Close button", + ) + } + } +} diff --git a/sample/shared/shared/src/androidMain/kotlin/com/arkivanov/sample/shared/root/RootView.kt b/sample/shared/shared/src/androidMain/kotlin/com/arkivanov/sample/shared/root/RootView.kt index 06c0fb0f3..88d5fbe7a 100644 --- a/sample/shared/shared/src/androidMain/kotlin/com/arkivanov/sample/shared/root/RootView.kt +++ b/sample/shared/shared/src/androidMain/kotlin/com/arkivanov/sample/shared/root/RootView.kt @@ -9,6 +9,7 @@ import com.arkivanov.sample.shared.R import com.arkivanov.sample.shared.root.RootComponent.Child.CustomNavigationChild import com.arkivanov.sample.shared.root.RootComponent.Child.DynamicFeaturesChild import com.arkivanov.sample.shared.root.RootComponent.Child.PagesChild +import com.arkivanov.sample.shared.root.RootComponent.Child.SharedTransitionsChild import com.arkivanov.sample.shared.root.RootComponent.Child.TabsChild import com.arkivanov.sample.shared.tabs.TabsView import com.arkivanov.sample.shared.viewSwitcher @@ -25,9 +26,11 @@ fun ViewContext.RootView(component: RootComponent): View { replaceChildView = viewSwitcher { child -> when (child) { is TabsChild -> TabsView(child.component) - is CustomNavigationChild -> error("Unsupported child: $child") - is DynamicFeaturesChild -> error("Unsupported child: $child") - is PagesChild -> error("Unsupported child: $child") + + is CustomNavigationChild, + is DynamicFeaturesChild, + is PagesChild, + is SharedTransitionsChild -> error("Unsupported child: $child") } }, ) diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/ImageResourceId.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/ImageResourceId.kt new file mode 100644 index 000000000..cc464180b --- /dev/null +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/ImageResourceId.kt @@ -0,0 +1,12 @@ +package com.arkivanov.sample.shared + +import kotlinx.serialization.Serializable + +@Serializable +enum class ImageResourceId { + CAT_1, + CAT_2, + CAT_3, + CAT_4, + CAT_5, +} diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/DefaultCustomNavigationComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/DefaultCustomNavigationComponent.kt index 42f92fc04..eff4e5731 100644 --- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/DefaultCustomNavigationComponent.kt +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/DefaultCustomNavigationComponent.kt @@ -8,9 +8,9 @@ import com.arkivanov.decompose.router.children.SimpleChildNavState import com.arkivanov.decompose.router.children.SimpleNavigation import com.arkivanov.decompose.router.children.children import com.arkivanov.decompose.value.Value +import com.arkivanov.sample.shared.ImageResourceId import com.arkivanov.sample.shared.customnavigation.CustomNavigationComponent.Children import com.arkivanov.sample.shared.customnavigation.CustomNavigationComponent.Mode -import com.arkivanov.sample.shared.customnavigation.KittenComponent.ImageType import kotlinx.serialization.Serializable class DefaultCustomNavigationComponent( @@ -27,9 +27,7 @@ class DefaultCustomNavigationComponent( key = "carousel", initialState = { NavigationState( - configurations = ImageType.values().map { imageType -> - Config(imageType = imageType) - }, + configurations = ImageResourceId.entries.map(::Config), index = 0, mode = Mode.CAROUSEL, ) @@ -50,7 +48,7 @@ class DefaultCustomNavigationComponent( childFactory = { config, componentContext -> DefaultKittenComponent( componentContext = componentContext, - imageType = config.imageType, + imageResourceId = config.imageResourceId, ) }, ) @@ -93,9 +91,7 @@ class DefaultCustomNavigationComponent( } @Serializable - private data class Config( - val imageType: ImageType, - ) + private data class Config(val imageResourceId: ImageResourceId) @Serializable private data class NavigationState( diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/DefaultKittenComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/DefaultKittenComponent.kt index 47156142c..c25223295 100644 --- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/DefaultKittenComponent.kt +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/DefaultKittenComponent.kt @@ -8,7 +8,7 @@ import com.arkivanov.decompose.value.update import com.arkivanov.essenty.instancekeeper.InstanceKeeper import com.arkivanov.essenty.instancekeeper.getOrCreate import com.arkivanov.essenty.lifecycle.subscribe -import com.arkivanov.sample.shared.customnavigation.KittenComponent.ImageType +import com.arkivanov.sample.shared.ImageResourceId import com.arkivanov.sample.shared.customnavigation.KittenComponent.Model import com.badoo.reaktive.disposable.Disposable import com.badoo.reaktive.observable.observableInterval @@ -18,7 +18,7 @@ import kotlinx.serialization.Serializable class DefaultKittenComponent( componentContext: ComponentContext, - private val imageType: ImageType, + private val imageResourceId: ImageResourceId, ) : KittenComponent, ComponentContext by componentContext { private val handler = @@ -39,7 +39,7 @@ class DefaultKittenComponent( private fun State.toModel(): Model = Model( - imageType = imageType, + imageResourceId = imageResourceId, text = count.toString().padStart(length = 3, padChar = '0'), ) diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/KittenComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/KittenComponent.kt index 4d0b4b413..c87d9cf73 100644 --- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/KittenComponent.kt +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/KittenComponent.kt @@ -1,23 +1,14 @@ package com.arkivanov.sample.shared.customnavigation import com.arkivanov.decompose.value.Value -import kotlinx.serialization.Serializable +import com.arkivanov.sample.shared.ImageResourceId interface KittenComponent { val model: Value data class Model( - val imageType: ImageType, + val imageResourceId: ImageResourceId, val text: String, ) - - @Serializable - enum class ImageType { - CAT_1, - CAT_2, - CAT_3, - CAT_4, - CAT_5, - } } diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/PreviewKittenComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/PreviewKittenComponent.kt new file mode 100644 index 000000000..ece2bfa9b --- /dev/null +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/customnavigation/PreviewKittenComponent.kt @@ -0,0 +1,11 @@ +package com.arkivanov.sample.shared.customnavigation + +import com.arkivanov.decompose.value.MutableValue +import com.arkivanov.decompose.value.Value +import com.arkivanov.sample.shared.ImageResourceId +import com.arkivanov.sample.shared.customnavigation.KittenComponent.Model + +class PreviewKittenComponent : KittenComponent { + + override val model: Value = MutableValue(Model(imageResourceId = ImageResourceId.CAT_1, text = "Kitten")) +} diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/menu/DefaultMenuComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/menu/DefaultMenuComponent.kt index 0505f3843..392211a4d 100644 --- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/menu/DefaultMenuComponent.kt +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/menu/DefaultMenuComponent.kt @@ -4,4 +4,5 @@ internal class DefaultMenuComponent( override val onDynamicFeaturesItemSelected: () -> Unit, override val onCustomNavigationItemSelected: () -> Unit, override val onPagesItemSelected: () -> Unit, + override val onSharedTransitionsItemSelected: () -> Unit, ) : MenuComponent diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/menu/MenuComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/menu/MenuComponent.kt index 16434f79a..78418a00d 100644 --- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/menu/MenuComponent.kt +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/menu/MenuComponent.kt @@ -5,4 +5,5 @@ interface MenuComponent { val onDynamicFeaturesItemSelected: () -> Unit val onCustomNavigationItemSelected: () -> Unit val onPagesItemSelected: () -> Unit + val onSharedTransitionsItemSelected: () -> Unit } diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/menu/PreviewMenuComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/menu/PreviewMenuComponent.kt index 337dfdbfd..c13c233f9 100644 --- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/menu/PreviewMenuComponent.kt +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/menu/PreviewMenuComponent.kt @@ -4,4 +4,5 @@ class PreviewMenuComponent : MenuComponent { override val onDynamicFeaturesItemSelected: () -> Unit = {} override val onCustomNavigationItemSelected: () -> Unit = {} override val onPagesItemSelected: () -> Unit = {} + override val onSharedTransitionsItemSelected: () -> Unit = {} } diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/pages/DefaultPagesComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/pages/DefaultPagesComponent.kt index c2209f4d7..7396eb98f 100644 --- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/pages/DefaultPagesComponent.kt +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/pages/DefaultPagesComponent.kt @@ -10,9 +10,9 @@ import com.arkivanov.decompose.router.pages.select import com.arkivanov.decompose.router.pages.selectNext import com.arkivanov.decompose.router.pages.selectPrev import com.arkivanov.decompose.value.Value +import com.arkivanov.sample.shared.ImageResourceId import com.arkivanov.sample.shared.customnavigation.DefaultKittenComponent import com.arkivanov.sample.shared.customnavigation.KittenComponent -import com.arkivanov.sample.shared.customnavigation.KittenComponent.ImageType import kotlinx.serialization.serializer @OptIn(ExperimentalDecomposeApi::class) @@ -21,13 +21,13 @@ class DefaultPagesComponent( private val onFinished: () -> Unit, ) : PagesComponent, ComponentContext by componentContext { - private val nav = PagesNavigation() + private val nav = PagesNavigation() override val pages: Value> = childPages( source = nav, - serializer = serializer(), - initialPages = { Pages(items = ImageType.entries, selectedIndex = 0) }, + serializer = serializer(), + initialPages = { Pages(items = ImageResourceId.entries, selectedIndex = 0) }, childFactory = { imageType, ctx -> DefaultKittenComponent(ctx, imageType) }, ) diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/root/DefaultRootComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/root/DefaultRootComponent.kt index 37385d08f..a112bb5f6 100644 --- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/root/DefaultRootComponent.kt +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/root/DefaultRootComponent.kt @@ -19,6 +19,7 @@ import com.arkivanov.sample.shared.root.RootComponent.Child.CustomNavigationChil import com.arkivanov.sample.shared.root.RootComponent.Child.DynamicFeaturesChild import com.arkivanov.sample.shared.root.RootComponent.Child.PagesChild import com.arkivanov.sample.shared.root.RootComponent.Child.TabsChild +import com.arkivanov.sample.shared.sharedtransitions.DefaultSharedTransitionsComponent import com.arkivanov.sample.shared.tabs.DefaultTabsComponent import kotlinx.serialization.Serializable @@ -61,6 +62,7 @@ class DefaultRootComponent( onDynamicFeaturesItemSelected = { nav.pushNew(Config.DynamicFeatures) }, onCustomNavigationItemSelected = { nav.pushNew(Config.CustomNavigation) }, onPagesItemSelected = { nav.pushNew(Config.Pages) }, + onSharedTransitionsItemSelected = { nav.pushNew(Config.SharedTransitions) }, ) ) @@ -88,6 +90,14 @@ class DefaultRootComponent( onFinished = nav::pop, ) ) + + is Config.SharedTransitions -> + Child.SharedTransitionsChild( + DefaultSharedTransitionsComponent( + componentContext = componentContext, + onFinished = nav::pop, + ) + ) } override fun onBackClicked() { @@ -102,6 +112,7 @@ class DefaultRootComponent( private const val WEB_PATH_DYNAMIC_FEATURES = "dynamic-features" private const val WEB_PATH_CUSTOM_NAVIGATION = "custom-navigation" private const val WEB_PATH_PAGES = "pages" + private const val WEB_PATH_SHARED_TRANSITIONS = "shared-transitions" private fun getInitialStack(webHistoryPaths: List?, deepLink: DeepLink): List = webHistoryPaths @@ -121,6 +132,7 @@ class DefaultRootComponent( Config.DynamicFeatures -> "/$WEB_PATH_DYNAMIC_FEATURES" Config.CustomNavigation -> "/$WEB_PATH_CUSTOM_NAVIGATION" Config.Pages -> "/$WEB_PATH_PAGES" + Config.SharedTransitions -> "/$WEB_PATH_SHARED_TRANSITIONS" } private fun getConfigForPath(path: String): Config = @@ -128,6 +140,7 @@ class DefaultRootComponent( WEB_PATH_DYNAMIC_FEATURES -> Config.DynamicFeatures WEB_PATH_CUSTOM_NAVIGATION -> Config.CustomNavigation WEB_PATH_PAGES -> Config.Pages + WEB_PATH_SHARED_TRANSITIONS -> Config.SharedTransitions else -> Config.Tabs } } @@ -145,6 +158,9 @@ class DefaultRootComponent( @Serializable data object Pages : Config + + @Serializable + data object SharedTransitions : Config } sealed interface DeepLink { diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/root/RootComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/root/RootComponent.kt index d7e5b731a..022a55ac8 100644 --- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/root/RootComponent.kt +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/root/RootComponent.kt @@ -6,6 +6,7 @@ import com.arkivanov.essenty.backhandler.BackHandlerOwner import com.arkivanov.sample.shared.customnavigation.CustomNavigationComponent import com.arkivanov.sample.shared.dynamicfeatures.DynamicFeaturesComponent import com.arkivanov.sample.shared.pages.PagesComponent +import com.arkivanov.sample.shared.sharedtransitions.SharedTransitionsComponent import com.arkivanov.sample.shared.tabs.TabsComponent interface RootComponent : BackHandlerOwner { @@ -20,5 +21,6 @@ interface RootComponent : BackHandlerOwner { class DynamicFeaturesChild(val component: DynamicFeaturesComponent) : Child() class CustomNavigationChild(val component: CustomNavigationComponent) : Child() class PagesChild(val component: PagesComponent) : Child() + class SharedTransitionsChild(val component: SharedTransitionsComponent) : Child() } } diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/DefaultSharedTransitionsComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/DefaultSharedTransitionsComponent.kt new file mode 100644 index 000000000..609787bb9 --- /dev/null +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/DefaultSharedTransitionsComponent.kt @@ -0,0 +1,61 @@ +package com.arkivanov.sample.shared.sharedtransitions + +import com.arkivanov.decompose.ComponentContext +import com.arkivanov.decompose.router.stack.ChildStack +import com.arkivanov.decompose.router.stack.StackNavigation +import com.arkivanov.decompose.router.stack.childStack +import com.arkivanov.decompose.router.stack.pop +import com.arkivanov.decompose.router.stack.pushNew +import com.arkivanov.decompose.value.Value +import com.arkivanov.sample.shared.sharedtransitions.SharedTransitionsComponent.Child +import com.arkivanov.sample.shared.sharedtransitions.SharedTransitionsComponent.Child.GalleryChild +import com.arkivanov.sample.shared.sharedtransitions.SharedTransitionsComponent.Child.PhotoChild +import com.arkivanov.sample.shared.sharedtransitions.gallery.DefaultGalleryComponent +import com.arkivanov.sample.shared.sharedtransitions.photo.DefaultPhotoComponent +import com.arkivanov.sample.shared.sharedtransitions.photo.Image +import kotlinx.serialization.Serializable + +class DefaultSharedTransitionsComponent( + componentContext: ComponentContext, + private val onFinished: () -> Unit, +) : SharedTransitionsComponent, ComponentContext by componentContext { + + private val nav = StackNavigation() + + override val stack: Value> = + childStack( + source = nav, + serializer = Config.serializer(), + initialConfiguration = Config.Gallery, + handleBackButton = true, + childFactory = { config, _ -> child(config) }, + ) + + private fun child(config: Config): Child = + when (config) { + is Config.Gallery -> + GalleryChild( + DefaultGalleryComponent( + onImageSelected = { nav.pushNew(Config.Photo(it)) }, + onFinished = onFinished, + ) + ) + + is Config.Photo -> + PhotoChild( + DefaultPhotoComponent( + image = config.image, + onFinished = nav::pop, + ) + ) + } + + @Serializable + private sealed interface Config { + @Serializable + data object Gallery : Config + + @Serializable + data class Photo(val image: Image) : Config + } +} diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/SharedTransitionsComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/SharedTransitionsComponent.kt new file mode 100644 index 000000000..0b5725030 --- /dev/null +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/SharedTransitionsComponent.kt @@ -0,0 +1,16 @@ +package com.arkivanov.sample.shared.sharedtransitions + +import com.arkivanov.decompose.router.stack.ChildStack +import com.arkivanov.decompose.value.Value +import com.arkivanov.sample.shared.sharedtransitions.gallery.GalleryComponent +import com.arkivanov.sample.shared.sharedtransitions.photo.PhotoComponent + +interface SharedTransitionsComponent { + + val stack: Value> + + sealed class Child { + class GalleryChild(val component: GalleryComponent) : Child() + class PhotoChild(val component: PhotoComponent) : Child() + } +} diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/gallery/DefaultGalleryComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/gallery/DefaultGalleryComponent.kt new file mode 100644 index 000000000..c0f13e5bb --- /dev/null +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/gallery/DefaultGalleryComponent.kt @@ -0,0 +1,26 @@ +package com.arkivanov.sample.shared.sharedtransitions.gallery + +import com.arkivanov.sample.shared.ImageResourceId +import com.arkivanov.sample.shared.sharedtransitions.photo.Image + +class DefaultGalleryComponent( + private val onImageSelected: (Image) -> Unit, + private val onFinished: () -> Unit, +) : GalleryComponent { + + override val images: List = + List(100) { index -> + Image( + id = index, + resourceId = ImageResourceId.entries[index % ImageResourceId.entries.size], + ) + } + + override fun onImageClicked(index: Int) { + onImageSelected(images[index]) + } + + override fun onCloseClicked() { + onFinished() + } +} diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/gallery/GalleryComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/gallery/GalleryComponent.kt new file mode 100644 index 000000000..a422746fe --- /dev/null +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/gallery/GalleryComponent.kt @@ -0,0 +1,11 @@ +package com.arkivanov.sample.shared.sharedtransitions.gallery + +import com.arkivanov.sample.shared.sharedtransitions.photo.Image + +interface GalleryComponent { + + val images: List + + fun onImageClicked(index: Int) + fun onCloseClicked() +} diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/gallery/PreviewGalleryComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/gallery/PreviewGalleryComponent.kt new file mode 100644 index 000000000..fe9e7aebd --- /dev/null +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/gallery/PreviewGalleryComponent.kt @@ -0,0 +1,18 @@ +package com.arkivanov.sample.shared.sharedtransitions.gallery + +import com.arkivanov.sample.shared.ImageResourceId +import com.arkivanov.sample.shared.sharedtransitions.photo.Image + +class PreviewGalleryComponent : GalleryComponent { + + override val images: List = + List(10) { index -> + Image( + id = index, + resourceId = ImageResourceId.entries[index % ImageResourceId.entries.size], + ) + } + + override fun onImageClicked(index: Int) {} + override fun onCloseClicked() {} +} diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/photo/DefaultPhotoComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/photo/DefaultPhotoComponent.kt new file mode 100644 index 000000000..0d54c2273 --- /dev/null +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/photo/DefaultPhotoComponent.kt @@ -0,0 +1,11 @@ +package com.arkivanov.sample.shared.sharedtransitions.photo + +class DefaultPhotoComponent( + override val image: Image, + private val onFinished: () -> Unit, +) : PhotoComponent { + + override fun onCloseClicked() { + onFinished() + } +} diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/photo/Image.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/photo/Image.kt new file mode 100644 index 000000000..646822184 --- /dev/null +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/photo/Image.kt @@ -0,0 +1,10 @@ +package com.arkivanov.sample.shared.sharedtransitions.photo + +import com.arkivanov.sample.shared.ImageResourceId +import kotlinx.serialization.Serializable + +@Serializable +data class Image( + val id: Int, + val resourceId: ImageResourceId, +) diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/photo/PhotoComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/photo/PhotoComponent.kt new file mode 100644 index 000000000..cc3810170 --- /dev/null +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/photo/PhotoComponent.kt @@ -0,0 +1,8 @@ +package com.arkivanov.sample.shared.sharedtransitions.photo + +interface PhotoComponent { + + val image: Image + + fun onCloseClicked() +} diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/photo/PreviewPhotoComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/photo/PreviewPhotoComponent.kt new file mode 100644 index 000000000..51797d348 --- /dev/null +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/sharedtransitions/photo/PreviewPhotoComponent.kt @@ -0,0 +1,10 @@ +package com.arkivanov.sample.shared.sharedtransitions.photo + +import com.arkivanov.sample.shared.ImageResourceId + +class PreviewPhotoComponent : PhotoComponent { + + override val image: Image = Image(id = 1, resourceId = ImageResourceId.CAT_1) + + override fun onCloseClicked() {} +} diff --git a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/tabs/DefaultTabsComponent.kt b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/tabs/DefaultTabsComponent.kt index 63630516b..0cd2b1b14 100644 --- a/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/tabs/DefaultTabsComponent.kt +++ b/sample/shared/shared/src/commonMain/kotlin/com/arkivanov/sample/shared/tabs/DefaultTabsComponent.kt @@ -22,6 +22,7 @@ internal class DefaultTabsComponent( private val onDynamicFeaturesItemSelected: () -> Unit, private val onCustomNavigationItemSelected: () -> Unit, private val onPagesItemSelected: () -> Unit, + private val onSharedTransitionsItemSelected: () -> Unit, ) : TabsComponent, ComponentContext by componentContext { private val nav = StackNavigation() @@ -42,6 +43,7 @@ internal class DefaultTabsComponent( onDynamicFeaturesItemSelected = onDynamicFeaturesItemSelected, onCustomNavigationItemSelected = onCustomNavigationItemSelected, onPagesItemSelected = onPagesItemSelected, + onSharedTransitionsItemSelected = onSharedTransitionsItemSelected, ) ) diff --git a/sample/shared/shared/src/commonTest/kotlin/com/arkivanov/sample/shared/tabs/TabsComponentIntegrationTest.kt b/sample/shared/shared/src/commonTest/kotlin/com/arkivanov/sample/shared/tabs/TabsComponentIntegrationTest.kt index 648afc9ca..31bbf4feb 100644 --- a/sample/shared/shared/src/commonTest/kotlin/com/arkivanov/sample/shared/tabs/TabsComponentIntegrationTest.kt +++ b/sample/shared/shared/src/commonTest/kotlin/com/arkivanov/sample/shared/tabs/TabsComponentIntegrationTest.kt @@ -52,6 +52,16 @@ class TabsComponentIntegrationTest { assertTrue(isCalled) } + @Test + fun WHEN_SharedTransitions_menu_item_clicked_THEN_onSharedTransitionsItemSelected_called() { + var isCalled = false + val component = createComponent(onSharedTransitionsItemSelected = { isCalled = true }) + + component.stack.activeInstance().component.onSharedTransitionsItemSelected() + + assertTrue(isCalled) + } + @Test fun WHEN_onCountersTabClicked_THEN_CountersTab_active() { val component = createComponent() @@ -94,6 +104,7 @@ class TabsComponentIntegrationTest { onDynamicFeaturesItemSelected: () -> Unit = {}, onCustomNavigationItemSelected: () -> Unit = {}, onPagesItemSelected: () -> Unit = {}, + onSharedTransitionsItemSelected: () -> Unit = {}, ): DefaultTabsComponent = createComponent { componentContext -> DefaultTabsComponent( @@ -101,6 +112,7 @@ class TabsComponentIntegrationTest { onDynamicFeaturesItemSelected = onDynamicFeaturesItemSelected, onCustomNavigationItemSelected = onCustomNavigationItemSelected, onPagesItemSelected = onPagesItemSelected, + onSharedTransitionsItemSelected = onSharedTransitionsItemSelected, ) } } diff --git a/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/root/RootContent.kt b/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/root/RootContent.kt index e0d78088f..483885e38 100644 --- a/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/root/RootContent.kt +++ b/sample/shared/shared/src/jsMain/kotlin/com/arkivanov/sample/shared/root/RootContent.kt @@ -5,6 +5,7 @@ import com.arkivanov.sample.shared.componentContent import com.arkivanov.sample.shared.root.RootComponent.Child.CustomNavigationChild import com.arkivanov.sample.shared.root.RootComponent.Child.DynamicFeaturesChild import com.arkivanov.sample.shared.root.RootComponent.Child.PagesChild +import com.arkivanov.sample.shared.root.RootComponent.Child.SharedTransitionsChild import com.arkivanov.sample.shared.root.RootComponent.Child.TabsChild import com.arkivanov.sample.shared.tabs.TabsContent import com.arkivanov.sample.shared.useAsState @@ -15,8 +16,10 @@ var RootContent: FC> = FC { props -> when (val child = stack.active.instance) { is TabsChild -> componentContent(component = child.component, content = TabsContent) - is CustomNavigationChild -> error("Unsupported child: $child") - is DynamicFeaturesChild -> error("Unsupported child: $child") - is PagesChild -> error("Unsupported child: $child") + + is CustomNavigationChild, + is DynamicFeaturesChild, + is PagesChild, + is SharedTransitionsChild -> error("Unsupported child: $child") } }