Skip to content

Commit 3fe3214

Browse files
authored
Merge pull request #2 from skydoves/feature/versioning
Implement versioning for components
2 parents 2e0800c + b84ac36 commit 3fe3214

File tree

9 files changed

+137
-29
lines changed

9 files changed

+137
-29
lines changed

core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/ConsumeDefaultUi.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ import io.getstream.server.driven.core.designsystem.theme.ServerDrivenTheme
2929
import io.getstream.server.driven.core.model.UiComponent
3030

3131
@Composable
32-
fun ConsumeDefaultUi(uiComponent: UiComponent) {
32+
fun ConsumeDefaultUi(
33+
uiComponent: UiComponent,
34+
version: Int
35+
) {
3336
Box(modifier = Modifier.fillMaxWidth()) {
3437
Text(
3538
modifier = Modifier.padding(6.dp),
@@ -44,7 +47,7 @@ fun ConsumeDefaultUi(uiComponent: UiComponent) {
4447
private fun ConsumeDefaultUiPreview() {
4548
ServerDrivenTheme {
4649
Box(modifier = Modifier.background(ServerDrivenTheme.colors.background)) {
47-
ConsumeDefaultUi(MockUtils.mockTextUi1)
50+
ConsumeDefaultUi(MockUtils.mockTextUi1, version = 1)
4851
}
4952
}
5053
}

core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/ConsumeImageUi.kt

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package io.getstream.server.driven.core.designsystem.consumer
1717

18+
import androidx.compose.foundation.border
1819
import androidx.compose.foundation.shape.RoundedCornerShape
1920
import androidx.compose.runtime.Composable
2021
import androidx.compose.ui.Modifier
@@ -34,10 +35,26 @@ import io.getstream.server.driven.core.model.ImageUi
3435
fun ConsumeImageUi(
3536
imageUi: ImageUi,
3637
modifier: Modifier = Modifier,
38+
version: Int,
3739
imageOptions: ImageOptions? = null
3840
) {
41+
val newModifier = if (version == 1) {
42+
modifier
43+
.size(imageUi.size)
44+
.clip(RoundedCornerShape(8.dp))
45+
} else {
46+
modifier
47+
.size(imageUi.size)
48+
.clip(RoundedCornerShape(16.dp))
49+
.border(
50+
width = 4.dp,
51+
color = ServerDrivenTheme.colors.primary,
52+
shape = RoundedCornerShape(16.dp)
53+
)
54+
}
55+
3956
GlideImage(
40-
modifier = modifier
57+
modifier = newModifier
4158
.size(imageUi.size)
4259
.clip(RoundedCornerShape(8.dp)),
4360
imageModel = { imageUi.url },
@@ -51,8 +68,16 @@ fun ConsumeImageUi(
5168

5269
@Preview
5370
@Composable
54-
private fun ConsumeImageUiPreview() {
71+
private fun ConsumeImageUiV1Preview() {
72+
ServerDrivenTheme {
73+
ConsumeImageUi(imageUi = MockUtils.mockImageUi, version = 1)
74+
}
75+
}
76+
77+
@Preview
78+
@Composable
79+
private fun ConsumeImageUiV2Preview() {
5580
ServerDrivenTheme {
56-
ConsumeImageUi(imageUi = MockUtils.mockImageUi)
81+
ConsumeImageUi(imageUi = MockUtils.mockImageUi, version = 2)
5782
}
5883
}

core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/ConsumeList.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import io.getstream.server.driven.core.model.typedValue
5454
fun ConsumeList(
5555
listUi: ListUi,
5656
modifier: Modifier = Modifier,
57+
version: Int,
5758
onListItemClicked: (UiComponent) -> Unit
5859
) {
5960
val layoutType = listUi.layout.toLayoutType()
@@ -78,7 +79,8 @@ fun ConsumeList(
7879
)
7980
) {
8081
ConsumeImageUi(
81-
imageUi = imageUi.copy(size = listUi.itemSize)
82+
imageUi = imageUi.copy(size = listUi.itemSize),
83+
version = version
8284
)
8385

8486
val like = listUi.extra["like"].typedValue(false)
@@ -124,7 +126,8 @@ private fun ConsumeListPreview() {
124126
ServerDrivenTheme {
125127
ConsumeList(
126128
listUi = MockUtils.mockListUi,
127-
onListItemClicked = {}
129+
onListItemClicked = {},
130+
version = 1
128131
)
129132
}
130133
}

core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/ConsumeTextUi.kt

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,29 +29,67 @@ import io.getstream.server.driven.core.model.TextUi
2929

3030
@Composable
3131
fun ConsumeTextUi(
32+
version: Int,
3233
textUi: TextUi,
3334
modifier: Modifier = Modifier
3435
) {
35-
Text(
36-
modifier = modifier,
37-
text = textUi.text,
38-
color = ServerDrivenTheme.colors.textHighEmphasis,
39-
fontSize = textUi.size.sp,
40-
fontWeight = textUi.fontWeight.toFontWeight()
41-
)
36+
if (version == 1) {
37+
Text(
38+
modifier = modifier,
39+
text = textUi.text,
40+
color = ServerDrivenTheme.colors.textHighEmphasis,
41+
fontSize = textUi.size.sp,
42+
fontWeight = textUi.fontWeight.toFontWeight()
43+
)
44+
} else {
45+
Text(
46+
modifier = modifier,
47+
text = textUi.text,
48+
color = ServerDrivenTheme.colors.primary,
49+
fontSize = textUi.size.sp,
50+
fontWeight = textUi.fontWeight.toFontWeight()
51+
)
52+
}
53+
}
54+
55+
@Preview
56+
@Composable
57+
private fun ConsumeTextUiV1Preview() {
58+
ServerDrivenTheme {
59+
Column(
60+
modifier = Modifier
61+
.background(ServerDrivenTheme.colors.background)
62+
.fillMaxWidth()
63+
) {
64+
ConsumeTextUi(
65+
version = 1,
66+
textUi = MockUtils.mockTextUi1
67+
)
68+
ConsumeTextUi(
69+
version = 1,
70+
textUi = MockUtils.mockTextUi2
71+
)
72+
}
73+
}
4274
}
4375

4476
@Preview
4577
@Composable
46-
private fun ConsumeTextUiPreview() {
78+
private fun ConsumeTextUiV2Preview() {
4779
ServerDrivenTheme {
4880
Column(
4981
modifier = Modifier
5082
.background(ServerDrivenTheme.colors.background)
5183
.fillMaxWidth()
5284
) {
53-
ConsumeTextUi(textUi = MockUtils.mockTextUi1)
54-
ConsumeTextUi(textUi = MockUtils.mockTextUi2)
85+
ConsumeTextUi(
86+
version = 2,
87+
textUi = MockUtils.mockTextUi1
88+
)
89+
ConsumeTextUi(
90+
version = 2,
91+
textUi = MockUtils.mockTextUi2
92+
)
5593
}
5694
}
5795
}

core/designsystem/src/main/kotlin/io/getstream/server/driven/core/designsystem/consumer/UiConsumer.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,19 @@ import io.getstream.server.driven.core.model.UiComponent
2525
@Composable
2626
fun UiComponent.Consume(
2727
modifier: Modifier = Modifier,
28+
version: Int = 0,
2829
onListItemClicked: (UiComponent) -> Unit = {}
2930
) {
3031
when (this) {
31-
is TextUi -> ConsumeTextUi(textUi = this, modifier = modifier)
32-
is ImageUi -> ConsumeImageUi(imageUi = this, modifier = modifier)
32+
is TextUi -> ConsumeTextUi(textUi = this, modifier = modifier, version = version)
33+
is ImageUi -> ConsumeImageUi(imageUi = this, modifier = modifier, version = version)
3334
is ListUi -> ConsumeList(
3435
listUi = this,
3536
modifier = modifier,
37+
version = version,
3638
onListItemClicked = onListItemClicked
3739
)
3840

39-
else -> ConsumeDefaultUi(uiComponent = this)
41+
else -> ConsumeDefaultUi(uiComponent = this, version = version)
4042
}
4143
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Designed and developed by 2024 skydoves (Jaewoong Eum)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.getstream.server.driven.core.model
17+
18+
import androidx.compose.runtime.Immutable
19+
20+
@Immutable
21+
data class ScreenUi(
22+
val version: Int,
23+
val components: List<UiComponent>
24+
)

core/model/src/main/kotlin/io/getstream/server/driven/core/model/TimelineUi.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import kotlinx.serialization.Serializable
1919

2020
@Serializable
2121
data class TimelineUi(
22+
val version: Int,
2223
val top: TimelineTopUi,
2324
val center: TimelineCenterUi,
2425
val bottom: TimelineBottomUi

feature/timeline/src/main/kotlin/io/getstream/server/driven/feature/timeline/Timeline.kt

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import io.getstream.server.driven.core.designsystem.preview.DefaultPreview
3737
import io.getstream.server.driven.core.designsystem.preview.MockUtils
3838
import io.getstream.server.driven.core.designsystem.theme.ServerDrivenTheme
3939
import io.getstream.server.driven.core.model.ImageUi
40+
import io.getstream.server.driven.core.model.ScreenUi
4041
import io.getstream.server.driven.core.model.UiComponent
4142

4243
@Composable
@@ -60,7 +61,7 @@ fun ServerDrivenTimeline(
6061

6162
@Composable
6263
private fun ServerDrivenTimelineContent(
63-
timelineUi: List<UiComponent>,
64+
timelineUi: ScreenUi,
6465
navigateToDetails: (UiComponent) -> Unit
6566
) {
6667
Column(
@@ -71,7 +72,7 @@ private fun ServerDrivenTimelineContent(
7172
.verticalScroll(state = rememberScrollState()),
7273
verticalArrangement = Arrangement.spacedBy(12.dp)
7374
) {
74-
timelineUi.forEach { uiComponent ->
75+
timelineUi.components.forEach { uiComponent ->
7576
val modifier = if (uiComponent is ImageUi) {
7677
Modifier.clickable { navigateToDetails.invoke(uiComponent) }
7778
} else {
@@ -80,6 +81,7 @@ private fun ServerDrivenTimelineContent(
8081

8182
uiComponent.Consume(
8283
modifier = modifier,
84+
version = timelineUi.version,
8385
onListItemClicked = { clickedComponent ->
8486
navigateToDetails.invoke(clickedComponent)
8587
}
@@ -93,10 +95,13 @@ private fun ServerDrivenTimelineContent(
9395
private fun ServerDrivenTimelineContentPreview() {
9496
ServerDrivenTheme {
9597
ServerDrivenTimelineContent(
96-
listOf(
97-
MockUtils.mockImageUi,
98-
MockUtils.mockTextUi1,
99-
MockUtils.mockTextUi2
98+
ScreenUi(
99+
version = 1,
100+
components = listOf(
101+
MockUtils.mockImageUi,
102+
MockUtils.mockTextUi1,
103+
MockUtils.mockTextUi2
104+
)
100105
),
101106
navigateToDetails = {}
102107
)

feature/timeline/src/main/kotlin/io/getstream/server/driven/feature/timeline/TimelineViewModel.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ import androidx.lifecycle.ViewModel
1919
import androidx.lifecycle.viewModelScope
2020
import dagger.hilt.android.lifecycle.HiltViewModel
2121
import io.getstream.server.driven.core.data.repository.TimelineRepository
22-
import io.getstream.server.driven.core.model.UiComponent
22+
import io.getstream.server.driven.core.model.ScreenUi
2323
import io.getstream.server.driven.core.model.buildUiComponentList
2424
import javax.inject.Inject
2525
import kotlinx.coroutines.flow.SharingStarted
2626
import kotlinx.coroutines.flow.StateFlow
27+
import kotlinx.coroutines.flow.filterNotNull
2728
import kotlinx.coroutines.flow.flatMapLatest
2829
import kotlinx.coroutines.flow.flowOf
2930
import kotlinx.coroutines.flow.map
@@ -34,9 +35,15 @@ class TimelineViewModel @Inject constructor(
3435
repository: TimelineRepository
3536
) : ViewModel() {
3637

37-
val timelineUi: StateFlow<List<UiComponent>?> = repository.fetchTimelineUi()
38+
val timelineUi: StateFlow<ScreenUi?> = repository.fetchTimelineUi()
3839
.flatMapLatest { response -> flowOf(response.getOrNull()) }
39-
.map { it?.buildUiComponentList() }
40+
.filterNotNull()
41+
.map {
42+
ScreenUi(
43+
version = it.version,
44+
components = it.buildUiComponentList()
45+
)
46+
}
4047
.stateIn(
4148
scope = viewModelScope,
4249
started = SharingStarted.WhileSubscribed(5000),

0 commit comments

Comments
 (0)