Skip to content

Commit f952cae

Browse files
committed
Improve loading UI by creating skeleton
1 parent 07e7957 commit f952cae

File tree

2 files changed

+60
-15
lines changed
  • core/ui/src/main/java/io/jja08111/gemini/core/ui
  • feature/rooms/ui/src/main/java/io/jja08111/gemini/feature/rooms/ui

2 files changed

+60
-15
lines changed

core/ui/src/main/java/io/jja08111/gemini/core/ui/CrossFade.kt

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ fun CrossFade(
6969
firstContent: @Composable () -> Unit,
7070
secondContent: @Composable () -> Unit,
7171
) {
72+
// TODO: Add height properties
7273
var firstContentWidth by remember { mutableStateOf(0) }
7374
var secondContentWidth by remember { mutableStateOf(0) }
7475

feature/rooms/ui/src/main/java/io/jja08111/gemini/feature/rooms/ui/RoomsScreen.kt

+59-15
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
package io.jja08111.gemini.feature.rooms.ui
22

33
import android.text.format.DateUtils
4+
import androidx.compose.foundation.background
45
import androidx.compose.foundation.clickable
56
import androidx.compose.foundation.layout.Box
67
import androidx.compose.foundation.layout.Column
8+
import androidx.compose.foundation.layout.Spacer
79
import androidx.compose.foundation.layout.fillMaxSize
810
import androidx.compose.foundation.layout.fillMaxWidth
11+
import androidx.compose.foundation.layout.height
912
import androidx.compose.foundation.layout.padding
13+
import androidx.compose.foundation.layout.size
1014
import androidx.compose.foundation.lazy.LazyColumn
1115
import androidx.compose.material.icons.Icons
1216
import androidx.compose.material.icons.filled.Add
13-
import androidx.compose.material3.CircularProgressIndicator
1417
import androidx.compose.material3.FloatingActionButton
1518
import androidx.compose.material3.Icon
1619
import androidx.compose.material3.LargeTopAppBar
@@ -22,14 +25,17 @@ import androidx.compose.material3.Text
2225
import androidx.compose.material3.TopAppBarDefaults
2326
import androidx.compose.material3.TopAppBarScrollBehavior
2427
import androidx.compose.runtime.Composable
28+
import androidx.compose.runtime.Stable
2529
import androidx.compose.ui.Alignment
2630
import androidx.compose.ui.Modifier
31+
import androidx.compose.ui.draw.clip
2732
import androidx.compose.ui.input.nestedscroll.nestedScroll
2833
import androidx.compose.ui.input.pointer.PointerEventPass
2934
import androidx.compose.ui.input.pointer.pointerInput
3035
import androidx.compose.ui.input.pointer.positionChange
3136
import androidx.compose.ui.res.stringResource
3237
import androidx.compose.ui.text.style.TextOverflow
38+
import androidx.compose.ui.tooling.preview.Preview
3339
import androidx.compose.ui.unit.dp
3440
import androidx.paging.LoadState
3541
import androidx.paging.compose.collectAsLazyPagingItems
@@ -61,17 +67,9 @@ fun RoomsScreen(
6167
val rooms = uiState.roomStream.collectAsLazyPagingItems()
6268
val loadState = rooms.loadState
6369
LazyColumn(modifier = Modifier.fillMaxSize()) {
64-
items(count = rooms.itemCount) { index ->
65-
val room = checkNotNull(rooms[index])
66-
RoomTile(
67-
modifier = Modifier.fillMaxWidth(),
68-
room = room,
69-
onClick = { onRoomClick(room.id) },
70-
)
71-
}
7270
when (val refreshState = loadState.refresh) {
7371
is LoadState.Loading -> {
74-
item { CircularProgressIndicator() }
72+
items(count = 5) { RoomTileSkeleton() }
7573
}
7674

7775
is LoadState.Error -> {
@@ -85,11 +83,20 @@ fun RoomsScreen(
8583
}
8684
}
8785

88-
else -> {}
86+
is LoadState.NotLoading -> {
87+
items(count = rooms.itemCount) { index ->
88+
val room = checkNotNull(rooms[index])
89+
RoomTile(
90+
modifier = Modifier.fillMaxWidth(),
91+
room = room,
92+
onClick = { onRoomClick(room.id) },
93+
)
94+
}
95+
}
8996
}
9097
when (val appendState = loadState.append) {
9198
is LoadState.Loading -> {
92-
item { CircularProgressIndicator() }
99+
item { RoomTileSkeleton() }
93100
}
94101

95102
is LoadState.Error -> {
@@ -103,7 +110,7 @@ fun RoomsScreen(
103110
}
104111
}
105112

106-
else -> {}
113+
is LoadState.NotLoading -> {}
107114
}
108115
}
109116
FloatingActionButton(
@@ -145,13 +152,18 @@ fun Modifier.verticalScrollDisabled() =
145152
}
146153
}
147154

155+
@Stable
156+
private fun Modifier.roomTilePadding(): Modifier {
157+
return this.padding(horizontal = 16.dp, vertical = 12.dp)
158+
}
159+
148160
// TODO: Show summarized user message.
149161
@Composable
150162
internal fun RoomTile(modifier: Modifier = Modifier, room: Room, onClick: () -> Unit) {
151163
Column(
152164
modifier = modifier
153165
.clickable(onClick = onClick)
154-
.padding(horizontal = 16.dp, vertical = 12.dp),
166+
.roomTilePadding(),
155167
) {
156168
Text(
157169
text = room.title ?: "New chat",
@@ -170,7 +182,31 @@ internal fun RoomTile(modifier: Modifier = Modifier, room: Room, onClick: () ->
170182
}
171183
}
172184

173-
fun LocalDateTime.toTimeSpanText(): String {
185+
@Composable
186+
private fun Modifier.skeletonStyle(): Modifier {
187+
return this
188+
.clip(shape = MaterialTheme.shapes.extraSmall)
189+
.background(color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.1f))
190+
}
191+
192+
@Composable
193+
private fun RoomTileSkeleton() {
194+
Column(modifier = Modifier.roomTilePadding()) {
195+
Box(
196+
modifier = Modifier
197+
.size(width = 184.dp, height = 20.dp)
198+
.skeletonStyle(),
199+
)
200+
Spacer(modifier = Modifier.height(8.dp))
201+
Box(
202+
modifier = Modifier
203+
.size(width = 60.dp, height = 16.dp)
204+
.skeletonStyle(),
205+
)
206+
}
207+
}
208+
209+
private fun LocalDateTime.toTimeSpanText(): String {
174210
val now = Instant.now().toEpochMilli()
175211
val defaultZone = ZoneId.systemDefault()
176212
return DateUtils.getRelativeTimeSpanString(
@@ -179,3 +215,11 @@ fun LocalDateTime.toTimeSpanText(): String {
179215
DateUtils.DAY_IN_MILLIS,
180216
).toString()
181217
}
218+
219+
@Composable
220+
@Preview(showBackground = true)
221+
private fun RoomTileSkeletonPreview() {
222+
MaterialTheme {
223+
RoomTileSkeleton()
224+
}
225+
}

0 commit comments

Comments
 (0)