From 46b4883fb007dcd23907b0a6e9c7c542a8f50324 Mon Sep 17 00:00:00 2001 From: skydoves Date: Thu, 5 Sep 2024 11:04:16 +0900 Subject: [PATCH] Implement handler and action systems --- .../designsystem/consumer/ConsumeHandler.kt | 42 +++++++++++++++++++ .../designsystem/consumer/ConsumeImageUi.kt | 8 ++++ .../core/designsystem/consumer/UiConsumer.kt | 14 +++++-- .../server/driven/core/model/Handler.kt | 34 +++++++++++++++ .../server/driven/core/model/ImageUi.kt | 3 +- .../server/driven/core/model/ListUi.kt | 1 + .../driven/feature/timeline/Timeline.kt | 11 +---- 7 files changed, 98 insertions(+), 15 deletions(-) create mode 100644 core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/ConsumeHandler.kt create mode 100644 core/model/src/main/kotlin/io/getstream/server/driven/core/model/Handler.kt diff --git a/core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/ConsumeHandler.kt b/core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/ConsumeHandler.kt new file mode 100644 index 0000000..2c59539 --- /dev/null +++ b/core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/ConsumeHandler.kt @@ -0,0 +1,42 @@ +/* + * Designed and developed by 2024 skydoves (Jaewoong Eum) + * + * 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. + * + * 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 io.getstream.server.driven.core.designsystem.consumer + +import androidx.compose.foundation.clickable +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import io.getstream.server.driven.core.model.Handler +import io.getstream.server.driven.core.model.HandlerAction +import io.getstream.server.driven.core.model.HandlerType + +@Composable +fun Handler?.consumeHandler( + navigator: () -> Unit +): Modifier { + if (this == null) return Modifier + + val action = if (this.actions[HandlerAction.NAVIGATION.value] == "to") { + { navigator } + } else { + {} + } + + return if (this.type == HandlerType.CLICK.value) { + Modifier.clickable { action.invoke() } + } else { + Modifier + } +} diff --git a/core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/ConsumeImageUi.kt b/core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/ConsumeImageUi.kt index 47cac27..748fa32 100644 --- a/core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/ConsumeImageUi.kt +++ b/core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/ConsumeImageUi.kt @@ -30,20 +30,28 @@ import io.getstream.server.driven.core.designsystem.extension.size import io.getstream.server.driven.core.designsystem.preview.MockUtils import io.getstream.server.driven.core.designsystem.theme.ServerDrivenTheme import io.getstream.server.driven.core.model.ImageUi +import io.getstream.server.driven.core.model.UiComponent @Composable fun ConsumeImageUi( imageUi: ImageUi, modifier: Modifier = Modifier, version: Int, + navigator: (UiComponent) -> Unit = {}, imageOptions: ImageOptions? = null ) { + val actionModifier = imageUi.handler.consumeHandler( + navigator = { navigator.invoke(imageUi) } + ) + val newModifier = if (version == 1) { modifier + .then(actionModifier) .size(imageUi.size) .clip(RoundedCornerShape(8.dp)) } else { modifier + .then(actionModifier) .size(imageUi.size) .clip(RoundedCornerShape(16.dp)) .border( diff --git a/core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/UiConsumer.kt b/core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/UiConsumer.kt index 87dafac..c496266 100644 --- a/core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/UiConsumer.kt +++ b/core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/UiConsumer.kt @@ -25,17 +25,23 @@ import io.getstream.server.driven.core.model.UiComponent @Composable fun UiComponent.Consume( modifier: Modifier = Modifier, - version: Int = 0, - onListItemClicked: (UiComponent) -> Unit = {} + version: Int = 1, + navigator: (UiComponent) -> Unit = {} ) { when (this) { is TextUi -> ConsumeTextUi(textUi = this, modifier = modifier, version = version) - is ImageUi -> ConsumeImageUi(imageUi = this, modifier = modifier, version = version) + is ImageUi -> ConsumeImageUi( + imageUi = this, + modifier = modifier, + version = version, + navigator = navigator + ) + is ListUi -> ConsumeList( listUi = this, modifier = modifier, version = version, - onListItemClicked = onListItemClicked + onListItemClicked = navigator ) else -> ConsumeDefaultUi(uiComponent = this, version = version) diff --git a/core/model/src/main/kotlin/io/getstream/server/driven/core/model/Handler.kt b/core/model/src/main/kotlin/io/getstream/server/driven/core/model/Handler.kt new file mode 100644 index 0000000..3217cf5 --- /dev/null +++ b/core/model/src/main/kotlin/io/getstream/server/driven/core/model/Handler.kt @@ -0,0 +1,34 @@ +/* + * Designed and developed by 2024 skydoves (Jaewoong Eum) + * + * 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. + * + * 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 io.getstream.server.driven.core.model + +import androidx.compose.runtime.Immutable +import kotlinx.serialization.Serializable + +@Immutable +@Serializable +data class Handler( + val type: String, + val actions: Map +) + +enum class HandlerType(val value: String) { + CLICK("click") +} + +enum class HandlerAction(val value: String) { + NAVIGATION("navigation") +} diff --git a/core/model/src/main/kotlin/io/getstream/server/driven/core/model/ImageUi.kt b/core/model/src/main/kotlin/io/getstream/server/driven/core/model/ImageUi.kt index cbbf2c5..8812831 100644 --- a/core/model/src/main/kotlin/io/getstream/server/driven/core/model/ImageUi.kt +++ b/core/model/src/main/kotlin/io/getstream/server/driven/core/model/ImageUi.kt @@ -24,7 +24,8 @@ data class ImageUi( val title: String = "", val url: String, val size: DpSizeUi = DpSizeUi(0, 0), - val scaleType: String + val scaleType: String, + val handler: Handler? = null ) : UiComponent { fun toTextUi( diff --git a/core/model/src/main/kotlin/io/getstream/server/driven/core/model/ListUi.kt b/core/model/src/main/kotlin/io/getstream/server/driven/core/model/ListUi.kt index 52ae115..a7d838b 100644 --- a/core/model/src/main/kotlin/io/getstream/server/driven/core/model/ListUi.kt +++ b/core/model/src/main/kotlin/io/getstream/server/driven/core/model/ListUi.kt @@ -25,6 +25,7 @@ data class ListUi( val layout: String, val itemSize: DpSizeUi, val items: List, + val handler: Handler? = null, val extra: Map = mapOf() ) : UiComponent diff --git a/feature/timeline/src/main/kotlin/io/getstream/server/driven/feature/timeline/Timeline.kt b/feature/timeline/src/main/kotlin/io/getstream/server/driven/feature/timeline/Timeline.kt index 32c59b4..ae3a913 100644 --- a/feature/timeline/src/main/kotlin/io/getstream/server/driven/feature/timeline/Timeline.kt +++ b/feature/timeline/src/main/kotlin/io/getstream/server/driven/feature/timeline/Timeline.kt @@ -16,7 +16,6 @@ package io.getstream.server.driven.feature.timeline import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -36,7 +35,6 @@ import io.getstream.server.driven.core.designsystem.consumer.Consume import io.getstream.server.driven.core.designsystem.preview.DefaultPreview import io.getstream.server.driven.core.designsystem.preview.MockUtils import io.getstream.server.driven.core.designsystem.theme.ServerDrivenTheme -import io.getstream.server.driven.core.model.ImageUi import io.getstream.server.driven.core.model.ScreenUi import io.getstream.server.driven.core.model.UiComponent @@ -73,16 +71,9 @@ private fun ServerDrivenTimelineContent( verticalArrangement = Arrangement.spacedBy(12.dp) ) { timelineUi.components.forEach { uiComponent -> - val modifier = if (uiComponent is ImageUi) { - Modifier.clickable { navigateToDetails.invoke(uiComponent) } - } else { - Modifier - } - uiComponent.Consume( - modifier = modifier, version = timelineUi.version, - onListItemClicked = { clickedComponent -> + navigator = { clickedComponent -> navigateToDetails.invoke(clickedComponent) } )