Skip to content

Commit

Permalink
Merge pull request #320 from apeun-gidaechi/feature/319-member-loadin…
Browse files Browse the repository at this point in the history
…g-shimmer

Feature/Member Loading Shimmer
  • Loading branch information
8954sood authored Oct 18, 2024
2 parents 0971a2c + 29d5656 commit 086a415
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.seugi.designsystem.component

import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.runtime.Composable
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color

@Composable
fun shimmerEffectBrush(showShimmer: Boolean = true, targetValue: Float = 1000f): Brush {
return if (showShimmer) {
// Colors for the shimmer effect
val shimmerColors = listOf(
Color.LightGray.copy(alpha = 0.6f),
Color.LightGray.copy(alpha = 0.2f),
Color.LightGray.copy(alpha = 0.6f),
)

// Start the animation transition
val transition = rememberInfiniteTransition(label = "")
val translateAnimation = transition.animateFloat(
initialValue = 0f,
targetValue = targetValue,
animationSpec = infiniteRepeatable(
animation = tween(800),
repeatMode = RepeatMode.Reverse,
),
label = "",
)

// Return a linear gradient brush
Brush.linearGradient(
colors = shimmerColors,
start = Offset.Zero,
end = Offset(x = translateAnimation.value, y = translateAnimation.value),
)
} else {
// If shimmer is turned off, return a transparent brush
Brush.linearGradient(
colors = listOf(Color.Transparent, Color.Transparent),
start = Offset.Zero,
end = Offset.Zero,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

@HiltViewModel
Expand All @@ -36,6 +37,11 @@ class RoomCreateViewModel @Inject constructor(
val sideEffect = _sideEffect.receiveAsFlow()

fun loadUser(workspaceId: String, userId: Int) = viewModelScope.launch(dispatcher) {
_state.update {
it.copy(
isLoading = true,
)
}
workspaceRepository.getMembers(workspaceId).collect {
when (it) {
is Result.Success -> {
Expand All @@ -52,6 +58,7 @@ class RoomCreateViewModel @Inject constructor(
}
_state.value = _state.value.copy(
userItem = users.filter { it.id != userId }.toImmutableList(),
isLoading = false,
)
}
is Result.Loading -> {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList

data class RoomCreateUiState(
val isLoading: Boolean = false,
val userItem: ImmutableList<RoomMemberItem> = persistentListOf(),
) {
val checkedMemberState: ImmutableList<RoomMemberItem> by lazy {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import com.seugi.designsystem.component.SeugiTopBar
import com.seugi.designsystem.component.modifier.verticalScrollbar
import com.seugi.designsystem.theme.SeugiTheme
import com.seugi.roomcreate.model.RoomCreateUiState
import com.seugi.ui.component.SeugiMemberListLoading
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

Expand Down Expand Up @@ -149,6 +150,17 @@ internal fun FirstScreen(state: RoomCreateUiState, updateChecked: (userId: Int)
LazyColumn(
modifier = Modifier.background(SeugiTheme.colors.white),
) {
if (state.isLoading) {
items(3) {
Box(
modifier = Modifier.height(72.dp),
contentAlignment = Alignment.Center,
) {
SeugiMemberListLoading()
}
}
}

items(
items = state.userItem,
key = { it.id },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import com.seugi.designsystem.component.SeugiTopBar
import com.seugi.designsystem.theme.SeugiTheme
import com.seugi.ui.CollectAsSideEffect
import com.seugi.ui.component.OtherProfileBottomSheet
import com.seugi.ui.component.SeugiMemberListLoading
import com.seugi.workspacedetail.feature.workspacemember.model.WorkspaceMemberSideEffect
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
Expand Down Expand Up @@ -200,6 +201,12 @@ fun WorkspaceMemberScreen(
}
}

if (state.isLoading) {
items(3) {
SeugiMemberListLoading()
}
}

items(items = student, key = { it.member.id }) { user ->
SeugiMemberList(
userName = user.member.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,21 @@ class WorkspaceMemberViewModel @Inject constructor(
private val _state = MutableStateFlow(WorkspaceMemberUiState())
val state = _state.asStateFlow()
fun getAllMember(workspaceId: String) {
if (_state.value.member.size == 0) {
_state.update {
it.copy(
isLoading = true,
)
}
}
viewModelScope.launch {
workspaceRepository.getMembers(workspaceId = workspaceId).collect {
when (it) {
is Result.Success -> {
_state.update { ui ->
ui.copy(
member = it.data.toImmutableList(),
isLoading = false,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf

data class WorkspaceMemberUiState(
val isLoading: Boolean = false,
val member: ImmutableList<ProfileModel> = persistentListOf(),
)
57 changes: 57 additions & 0 deletions ui/src/main/java/com/seugi/ui/component/SeugiMemberListLoading.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.seugi.ui.component

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.seugi.designsystem.component.shimmerEffectBrush

@Composable
fun SeugiMemberListLoading(modifier: Modifier = Modifier) {
Row(
modifier = modifier
.fillMaxWidth()
.height(56.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Row(
modifier = Modifier.padding(
horizontal = 16.dp,
vertical = 10.dp,
),
verticalAlignment = Alignment.CenterVertically,
) {
Box(
modifier = Modifier
.size(36.dp)
.background(
brush = shimmerEffectBrush(),
shape = CircleShape,
),
)
Spacer(modifier = Modifier.width(16.dp))

Box(
modifier = Modifier
.width(52.dp)
.height(21.dp)
.background(
brush = shimmerEffectBrush(),
shape = RoundedCornerShape(12.dp),
),
)
Spacer(modifier = Modifier.weight(1f))
}
}
}

0 comments on commit 086a415

Please sign in to comment.