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
@@ -1,6 +1,5 @@
package com.afternote.feature.receiver.presentation.home

import android.widget.Toast
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
Expand All @@ -12,17 +11,18 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalResources
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.afternote.core.ui.button.AfternoteButton
Expand Down Expand Up @@ -51,6 +51,7 @@ fun ReceiverHomeScreen(
actions: ReceiverHomeActions,
modifier: Modifier = Modifier,
) {
val snackbarHostState = remember { SnackbarHostState() }
Scaffold(
modifier = modifier,
containerColor = Color.Transparent,
Expand All @@ -60,6 +61,7 @@ fun ReceiverHomeScreen(
onSettingClick = actions.onSettingClick,
)
},
snackbarHost = { SnackbarHost(snackbarHostState) },
) { innerPadding ->
when (uiState) {
ReceiverHomeUiState.Loading -> { }
Expand All @@ -80,6 +82,7 @@ fun ReceiverHomeScreen(
)
DownloadDialogHost(
state = uiState.download,
snackbarHostState = snackbarHostState,
onEvent = onEvent,
)
}
Expand Down Expand Up @@ -141,13 +144,20 @@ private fun SuccessContent(
}
}

/**
* 내려받기 확인 팝업 + 결과 처리.
*
* 실패 안내는 잠정 Snackbar 다 — 서버 작업 실패의 정본은 #446 공통 에러 팝업이라 컴포넌트가
* 나오면 그쪽으로 재정렬된다 (#1391, #713 전례). `showSnackbar` 는 표출이 끝날 때까지 suspend
* 하므로 소비 이벤트는 표출 뒤에 보낸다 — 표출 중에는 [state] 가 Failed 로 유지돼 effect 가
* 재시작되지 않고, 소비로 Idle 이 되면 이미 완료된 effect 만 정리된다 (#664 AddSongScreen 컨벤션).
*/
@Composable
private fun DownloadDialogHost(
state: ReceiverDownloadState,
snackbarHostState: SnackbarHostState,
onEvent: (ReceiverHomeEvent) -> Unit,
) {
val context = LocalContext.current
val resources = LocalResources.current
val currentOnEvent by rememberUpdatedState(onEvent)

val showDialog =
Expand All @@ -162,19 +172,22 @@ private fun DownloadDialogHost(
)
}

LaunchedEffect(state) {
when (state) {
is ReceiverDownloadState.Failed -> {
Toast.makeText(context, resources.getString(state.messageRes), Toast.LENGTH_SHORT).show()
when (state) {
is ReceiverDownloadState.Failed -> {
val message = stringResource(state.messageRes)
LaunchedEffect(state) {
snackbarHostState.showSnackbar(message = message, withDismissAction = true)
currentOnEvent(ReceiverHomeEvent.ConsumeDownloadResult)
}
}

ReceiverDownloadState.Done -> {
ReceiverDownloadState.Done -> {
LaunchedEffect(state) {
currentOnEvent(ReceiverHomeEvent.ConsumeDownloadResult)
}

else -> { }
}

else -> { }
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.afternote.feature.receiver.presentation.home

import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.v2.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import com.afternote.core.ui.theme.AfternoteTheme
import com.afternote.feature.receiver.presentation.R
import com.afternote.feature.receiver.presentation.home.model.ReceiverDownloadState
import com.afternote.feature.receiver.presentation.home.model.ReceiverHomeUiState
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.robolectric.annotation.GraphicsMode

/**
* 수신자 홈 내려받기 실패 안내의 Snackbar 표출 가드 (#1391).
*
* 종전 Toast 는 Compose semantics 에 잡히지 않아 어떤 테스트로도 단언할 수 없었다 — 이 단언이
* 가능해진 것 자체가 전환 목적의 일부다. 문구는 리소스 원문으로 대조한다 (모듈 테스트 관례,
* [com.afternote.feature.receiver.presentation.deliveryverification.ReceiverVerificationTest] 참조).
*/
@RunWith(RobolectricTestRunner::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(sdk = [35])
class ReceiverHomeDownloadSnackbarTest {
@get:Rule
val composeRule = createComposeRule()

@Test
fun `내려받기 실패 상태는 스낵바로 표출된다`() {
setHomeContent(ReceiverDownloadState.Failed(R.string.receiver_home_download_all_failed))

composeRule.onNodeWithText("모든 기록 내려받기에 실패했습니다.").assertIsDisplayed()
}

@Test
fun `파일 저장 실패 상태도 자기 문구로 표출된다`() {
setHomeContent(ReceiverDownloadState.Failed(R.string.receiver_home_download_all_save_failed))

composeRule.onNodeWithText("파일 저장에 실패했습니다.").assertIsDisplayed()
}

private fun setHomeContent(download: ReceiverDownloadState) {
composeRule.setContent {
AfternoteTheme {
ReceiverHomeScreen(
uiState =
ReceiverHomeUiState.Success(
senderName = "박서연",
senderMessage = null,
mindRecord = null,
timeLetterTotalCount = null,
afternoteTotalCount = null,
afternoteIcons = emptyList(),
download = download,
),
onEvent = { },
actions = ReceiverHomeActions.Noop,
)
}
}
}
}
Loading