Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
Expand Down Expand Up @@ -146,6 +147,7 @@ private fun ArchiveDetailFrame(
topBar = {
ArchiveDetailTopBar(
emotion = emotion,
isClearEnabled = state.isClearable,
onBackClick = onBackClick,
onClearClick = onClearClick,
)
Expand Down Expand Up @@ -253,6 +255,7 @@ private fun ClearConfirmDialog(
@Composable
private fun ArchiveDetailTopBar(
emotion: EmotionCharacter,
isClearEnabled: Boolean,
onBackClick: () -> Unit,
onClearClick: () -> Unit,
) {
Expand Down Expand Up @@ -282,10 +285,10 @@ private fun ArchiveDetailTopBar(
Text(
text = stringResource(R.string.archive_clear),
style = GamssTheme.typography.body4Medium,
color = GamssTheme.colors.gray900,
color = if (isClearEnabled) GamssTheme.colors.gray900 else GamssTheme.colors.gray300,
modifier = Modifier
.clip(RoundedCornerShape(ClearRippleRadius))
.clickable(role = Role.Button, onClick = onClearClick)
.clickable(enabled = isClearEnabled, role = Role.Button, onClick = onClearClick)
.padding(ClearHitPadding),
)
},
Expand All @@ -302,25 +305,33 @@ private fun ArchiveDetailCards(
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
when (cardsState) {
ArchiveCards.Loading -> CircularProgressIndicator(color = GamssTheme.colors.gray700)
ArchiveCards.LoadFailed -> EmptyMessage(textRes = R.string.archive_cards_load_failed)
// 카드가 없으면 아무것도 그리지 않는다. 빈 종이판이 그대로 보이는 것이 이 화면의 빈 상태다.
ArchiveCards.LoadFailed -> EmptyMessage(
textRes = R.string.archive_cards_load_failed,
style = GamssTheme.typography.body4Medium,
)
is ArchiveCards.Loaded -> if (cardsState.cards.isNotEmpty()) {
PaperPile(
cards = cardsState.cards,
droppedCardId = droppedCardId,
onDropConsumed = onDropConsumed,
onPaperClick = onPaperClick,
)
} else {
// 조회 실패 문구와 구분되도록 iOS 와 같은 스타일을 쓴다.
EmptyMessage(
textRes = R.string.archive_cards_empty,
style = GamssTheme.typography.body3Regular,
)
}
}
}
}

@Composable
private fun EmptyMessage(@StringRes textRes: Int) {
private fun EmptyMessage(@StringRes textRes: Int, style: TextStyle) {
Text(
text = stringResource(textRes),
style = GamssTheme.typography.body4Medium,
style = style,
color = GamssTheme.colors.gray500,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ data class ArchiveDetailState(
val selectedCard: Card? = null,
val conversationCard: ConversationCard? = null,
val isConversationLoading: Boolean = false,
)
) {
/** 감정 칸 전체 카드 수는 알 수 없어, 보고 있는 달에 카드가 있을 때만 비울 수 있다. */
val isClearable: Boolean
get() = cards is ArchiveCards.Loaded && cards.cards.isNotEmpty()
}

/** 종이 더미 자리가 가질 수 있는 상태. 셋이 겹칠 수 없어 플래그 조합 대신 하나로 든다. */
sealed interface ArchiveCards {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class ArchiveDetailViewModel @Inject constructor(
}

fun showClearDialog() = intent {
if (!state.isClearable) return@intent
reduce { state.copy(isClearDialogVisible = true) }
}

Expand Down
1 change: 1 addition & 0 deletions feature/archive/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<string name="archive_back_description">뒤로 가기</string>
<string name="archive_paper_description">%1$d월 %2$d일 카드</string>
<string name="archive_cards_load_failed">이야기를 불러오지 못했어요.</string>
<string name="archive_cards_empty">아직 남겨둔 이야기가 없어요.</string>

<string name="archive_clear">비우기</string>
<string name="archive_clear_dialog_title">%1$s 기록 비우기</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,67 @@ class ArchiveDetailViewModelTest {
}
}

@Test
fun `보고 있는 달에 카드가 없으면 비우기 다이얼로그를 띄우지 않는다`() = runTest {
val viewModel = viewModel(FakeCardRepository(AppResult.Success(emptyList())))
val testScope = this

viewModel.test(this) {
containerHost.load(EmotionCharacter.ANGER)
expectState { copy(emotion = EmotionCharacter.ANGER) }
expectState { copy(cards = ArchiveCards.Loaded(emptyList())) }

containerHost.showClearDialog()
testScope.runCurrent()
expectNoItems()
}
}

@Test
fun `카드 조회에 실패하면 비우기 다이얼로그를 띄우지 않는다`() = runTest {
val viewModel = viewModel(FakeCardRepository(AppResult.Failure(IllegalStateException("network"))))
val testScope = this

viewModel.test(this) {
containerHost.load(EmotionCharacter.ANGER)
expectState { copy(emotion = EmotionCharacter.ANGER) }
expectState { copy(cards = ArchiveCards.LoadFailed) }

containerHost.showClearDialog()
testScope.runCurrent()
expectNoItems()
}
}

@Test
fun `다른 달 카드를 받아 오는 중에는 비우기 다이얼로그를 띄우지 않는다`() = runTest {
val slowMonth = YearMonth.now(KoreanTimeZone).minusMonths(1)
val slowMonthGate = CompletableDeferred<Unit>()
val repository = FakeCardRepository(
monthResult = AppResult.Success(listOf(angerCard)),
monthGates = mapOf(slowMonth to slowMonthGate),
)
val viewModel = viewModel(repository)
val testScope = this

viewModel.test(this) {
containerHost.load(EmotionCharacter.ANGER)
expectState { copy(emotion = EmotionCharacter.ANGER) }
expectState { copy(cards = ArchiveCards.Loaded(listOf(angerCard))) }

// 직전 달에 카드가 있었어도 새 달 목록이 오기 전에는 비울 수 없다.
containerHost.selectMonth(slowMonth)
expectState { copy(yearMonth = slowMonth, cards = ArchiveCards.Loading) }

containerHost.showClearDialog()
testScope.runCurrent()
expectNoItems()

slowMonthGate.complete(Unit)
expectState { copy(cards = ArchiveCards.Loaded(listOf(angerCard))) }
}
}

private fun viewModel(
repository: FakeCardRepository,
conversationRepository: FakeConversationRepository = FakeConversationRepository(),
Expand Down
Loading