diff --git a/core/design-system/src/main/java/com/easyhz/noffice/core/design_system/component/card/ItemCard.kt b/core/design-system/src/main/java/com/easyhz/noffice/core/design_system/component/card/ItemCard.kt index e31f4bb9..c1850ebc 100644 --- a/core/design-system/src/main/java/com/easyhz/noffice/core/design_system/component/card/ItemCard.kt +++ b/core/design-system/src/main/java/com/easyhz/noffice/core/design_system/component/card/ItemCard.kt @@ -32,6 +32,7 @@ import androidx.compose.ui.unit.dp import com.easyhz.noffice.core.design_system.R import com.easyhz.noffice.core.design_system.component.image.AnnouncementImage import com.easyhz.noffice.core.design_system.extension.screenHorizonPadding +import com.easyhz.noffice.core.design_system.extension.skeletonEffect import com.easyhz.noffice.core.design_system.theme.CardExceptionSubTitle import com.easyhz.noffice.core.design_system.theme.CardExceptionTitle import com.easyhz.noffice.core.design_system.theme.Grey200 @@ -57,14 +58,17 @@ fun ItemCard( .border(1.dp, color = Grey200, RoundedCornerShape(16.dp)) ) { AnnouncementImage( - modifier = Modifier.fillMaxWidth().height(160.dp), + modifier = Modifier + .fillMaxWidth() + .height(160.dp), imageUrl = imageUrl ) - Box(modifier = Modifier - .screenHorizonPadding() - .padding(start = 4.dp) - .fillMaxWidth() - .heightIn(min = 52.dp) + Box( + modifier = Modifier + .screenHorizonPadding() + .padding(start = 4.dp) + .fillMaxWidth() + .heightIn(min = 52.dp) ) { Text( modifier = Modifier.align(Alignment.CenterStart), @@ -74,11 +78,13 @@ fun ItemCard( overflow = TextOverflow.Ellipsis ) } - Spacer(modifier = Modifier - .screenHorizonPadding() - .height(1.dp) - .fillMaxWidth() - .border(1.dp, color = Grey200)) + Spacer( + modifier = Modifier + .screenHorizonPadding() + .height(1.dp) + .fillMaxWidth() + .border(1.dp, color = Grey200) + ) DetailFields( modifier = Modifier .screenHorizonPadding() @@ -88,6 +94,72 @@ fun ItemCard( } } +@Composable +fun SkeletonItemCard( + modifier: Modifier = Modifier +) { + Column( + modifier = modifier + .width(283.dp) + .height(296.dp) + .clip(RoundedCornerShape(16.dp)) + .border(1.dp, color = Grey200, RoundedCornerShape(16.dp)) + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(160.dp) + .skeletonEffect(), + ) + /* 타이틀 */ + Box( + modifier = Modifier + .screenHorizonPadding() + .padding(start = 4.dp) + .fillMaxWidth() + .heightIn(min = 52.dp) + ) { + Box( + modifier = Modifier + .align(Alignment.CenterStart) + .height(20.dp) + .fillMaxWidth(0.7f) + .clip(RoundedCornerShape(8.dp)) + .skeletonEffect(), + ) + } + Spacer( + modifier = Modifier + .screenHorizonPadding() + .height(1.dp) + .fillMaxWidth() + .border(1.dp, color = Grey200) + ) + /* DetailFields */ + Column( + modifier = modifier + .screenHorizonPadding() + .padding(top = 15.dp, start = 4.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Box( + modifier = Modifier + .height(18.dp) + .fillMaxWidth(0.5f) + .clip(RoundedCornerShape(8.dp)) + .skeletonEffect() + ) + Box( + modifier = Modifier + .height(18.dp) + .fillMaxWidth(0.7f) + .clip(RoundedCornerShape(8.dp)) + .skeletonEffect() + ) + } + } +} + @Composable private fun DetailFields( modifier: Modifier = Modifier, @@ -138,14 +210,19 @@ fun ExceptionCard( modifier: Modifier = Modifier, type: CardExceptionType ) { - Column(modifier = modifier - .width(283.dp) - .height(296.dp) - .clip(RoundedCornerShape(16.dp)) - .border(1.dp, color = Grey200, RoundedCornerShape(16.dp)), + Column( + modifier = modifier + .width(283.dp) + .height(296.dp) + .clip(RoundedCornerShape(16.dp)) + .border(1.dp, color = Grey200, RoundedCornerShape(16.dp)), verticalArrangement = Arrangement.spacedBy(6.dp) ) { - Box(modifier = Modifier.fillMaxWidth().weight(1f)) { + Box( + modifier = Modifier + .fillMaxWidth() + .weight(1f) + ) { Image( modifier = Modifier.align(Alignment.BottomCenter), painter = painterResource(id = type.resId), @@ -153,9 +230,10 @@ fun ExceptionCard( contentDescription = type.name ) } - Column(modifier = Modifier - .fillMaxWidth() - .weight(0.8f), + Column( + modifier = Modifier + .fillMaxWidth() + .weight(0.8f), verticalArrangement = Arrangement.spacedBy(6.dp), horizontalAlignment = Alignment.CenterHorizontally ) { diff --git a/feature/home/src/main/java/com/easyhz/noffice/feature/home/component/common/Header.kt b/feature/home/src/main/java/com/easyhz/noffice/feature/home/component/common/Header.kt index 2e0a665a..df8ade67 100644 --- a/feature/home/src/main/java/com/easyhz/noffice/feature/home/component/common/Header.kt +++ b/feature/home/src/main/java/com/easyhz/noffice/feature/home/component/common/Header.kt @@ -9,15 +9,18 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.sizeIn +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Text import androidx.compose.material3.Icon import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.easyhz.noffice.core.design_system.R +import com.easyhz.noffice.core.design_system.extension.skeletonEffect import com.easyhz.noffice.core.design_system.theme.Grey800 import com.easyhz.noffice.core.design_system.theme.InputDialogTitle @@ -49,6 +52,31 @@ internal fun OrganizationHeader( } } +@Composable +internal fun SkeletonOrganizationHeader( + modifier: Modifier = Modifier, +) { + + Row( + modifier = modifier.padding(horizontal = 14.dp).fillMaxWidth().fillMaxHeight(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + Box(modifier = Modifier.height(20.dp).fillMaxWidth(0.3f).clip(RoundedCornerShape(8.dp)).skeletonEffect()) + Box(modifier = Modifier + .sizeIn(minWidth = 32.dp, minHeight = 32.dp) + .fillMaxHeight() + ) { + Icon( + modifier = Modifier.align(Alignment.CenterEnd), + painter = painterResource(id = R.drawable.ic_chevron_right), + contentDescription = "rightArrow", + tint = Grey800 + ) + } + } +} + @Preview(showBackground = true) @Composable private fun Prev() { diff --git a/feature/home/src/main/java/com/easyhz/noffice/feature/home/component/notice/NoticeView.kt b/feature/home/src/main/java/com/easyhz/noffice/feature/home/component/notice/NoticeView.kt index 572c478d..378d712d 100644 --- a/feature/home/src/main/java/com/easyhz/noffice/feature/home/component/notice/NoticeView.kt +++ b/feature/home/src/main/java/com/easyhz/noffice/feature/home/component/notice/NoticeView.kt @@ -48,13 +48,19 @@ fun NoticeView( Banner(userName = name, date = dayOfWeek) } } - items(organizationList.itemCount) { index -> - organizationList[index]?.let { - OrganizationSection( - organization = it, - isRefreshing = isRefreshing, - navigateToAnnouncementDetail = {id, title -> navigateToAnnouncementDetail(it.id, id, title) } - ) + if(isLoading) { + items(2) { + SkeletonOrganizationSection() + } + } else { + items(organizationList.itemCount) { index -> + organizationList[index]?.let { + OrganizationSection( + organization = it, + isRefreshing = isRefreshing, + navigateToAnnouncementDetail = {id, title -> navigateToAnnouncementDetail(it.id, id, title) } + ) + } } } } diff --git a/feature/home/src/main/java/com/easyhz/noffice/feature/home/component/notice/SkeletonOrganizationSection.kt b/feature/home/src/main/java/com/easyhz/noffice/feature/home/component/notice/SkeletonOrganizationSection.kt new file mode 100644 index 00000000..78404d5f --- /dev/null +++ b/feature/home/src/main/java/com/easyhz/noffice/feature/home/component/notice/SkeletonOrganizationSection.kt @@ -0,0 +1,38 @@ +package com.easyhz.noffice.feature.home.component.notice + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.easyhz.noffice.core.design_system.component.card.SkeletonItemCard +import com.easyhz.noffice.core.design_system.extension.screenHorizonPadding +import com.easyhz.noffice.feature.home.component.common.SkeletonOrganizationHeader + +@Composable +internal fun SkeletonOrganizationSection( + modifier: Modifier = Modifier, +) { + Column(modifier) { + SkeletonOrganizationHeader( + modifier = Modifier + .fillMaxWidth() + .height(72.dp) + .screenHorizonPadding() + .padding(vertical = 8.dp), + ) + LazyRow( + userScrollEnabled = false, + modifier = Modifier.padding(start = 16.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp), + ) { + items(2) { + SkeletonItemCard() + } + } + } +} \ No newline at end of file diff --git a/feature/home/src/main/java/com/easyhz/noffice/feature/home/screen/home/HomeScreen.kt b/feature/home/src/main/java/com/easyhz/noffice/feature/home/screen/home/HomeScreen.kt index 7184afe8..c0393ccc 100644 --- a/feature/home/src/main/java/com/easyhz/noffice/feature/home/screen/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/easyhz/noffice/feature/home/screen/home/HomeScreen.kt @@ -55,7 +55,7 @@ fun HomeScreen( val organizationList = viewModel.organizationState.collectAsLazyPagingItems() val organizationIdToJoin = remember { DeepLinkManager.organizationIdToJoin } val context = LocalContext.current - val isRefreshing = remember(organizationList.loadState.refresh) { + val isRefreshing = remember(organizationList.loadState.refresh) { organizationList.loadState.refresh == LoadState.Loading } val pullRefreshState = rememberPullRefreshState( @@ -96,10 +96,12 @@ fun HomeScreen( } } ) { paddingValues -> - Box(modifier = Modifier - .pullRefresh(pullRefreshState) - .padding(top = paddingValues.calculateTopPadding())) { - if(organizationList.itemCount == 0 && !isRefreshing) { + Box( + modifier = Modifier + .pullRefresh(pullRefreshState) + .padding(top = paddingValues.calculateTopPadding()) + ) { + if (organizationList.itemCount == 0 && !isRefreshing) { ExceptionView( modifier = Modifier.fillMaxSize(), type = ExceptionType.NO_ORGANIZATION @@ -123,8 +125,10 @@ fun HomeScreen( } HomeTopBarMenu.TASK -> { - TaskView(modifier = Modifier - .screenHorizonPadding()) + TaskView( + modifier = Modifier + .screenHorizonPadding() + ) } } } @@ -141,17 +145,22 @@ fun HomeScreen( } viewModel.sideEffect.collectInSideEffectWithLifecycle { sideEffect -> - when(sideEffect) { - is HomeSideEffect.NavigateToMyPage -> { navigateToMyPage() } + when (sideEffect) { + is HomeSideEffect.NavigateToMyPage -> { + navigateToMyPage() + } + is HomeSideEffect.NavigateToOrganizationJoin -> { navigateToOrganizationJoin(sideEffect.organizationSignUpInformation) } + is HomeSideEffect.ShowSnackBar -> { snackBarHostState.showSnackbar( message = context.getString(sideEffect.stringId), withDismissAction = true ) } + is HomeSideEffect.Refresh -> { organizationList.refresh() }