From c3477d3c109abf537121a71b3080b6912b6c3ec7 Mon Sep 17 00:00:00 2001 From: Yerim Son Date: Sun, 18 Jan 2026 13:58:34 +0900 Subject: [PATCH 1/8] [Feat/#56] HistoryListScreen UI --- .../history/list/HistoryListScreen.kt | 195 +++++++++++++++++- .../history/list/model/HistoryListUiState.kt | 24 +++ 2 files changed, 212 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/com/poti/android/presentation/history/list/model/HistoryListUiState.kt diff --git a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt index 24d760c7..82cf025e 100644 --- a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt +++ b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt @@ -1,18 +1,199 @@ package com.poti.android.presentation.history.list -import androidx.compose.material3.Text +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.poti.android.R +import com.poti.android.core.designsystem.component.navigation.PotiHeaderPage +import com.poti.android.core.designsystem.component.navigation.PotiHeaderSection +import com.poti.android.core.designsystem.component.navigation.PotiHeaderTabType +import com.poti.android.core.designsystem.theme.PotiTheme +import com.poti.android.presentation.history.component.CardHistorySize +import com.poti.android.presentation.history.component.HistoryCardItem +import com.poti.android.presentation.history.component.ParticipantStateLabelStage +import com.poti.android.presentation.history.component.ParticipantStateLabelStatus +import com.poti.android.presentation.history.list.model.HistoryItem +import com.poti.android.presentation.history.list.model.HistoryListUiState -@Composable -fun HistoryListRoute(modifier: Modifier = Modifier) { - HistoryListScreen(modifier = modifier) +enum class HistoryMode { + RECRUIT, + PARTICIPATION, } @Composable -private fun HistoryListScreen(modifier: Modifier = Modifier) { - Text( - text = "분철 내역", +fun HistoryListRoute( + onBackClick: () -> Unit = {}, + onSwitchModeClick: () -> Unit = {}, + onTabSelected: (PotiHeaderTabType) -> Unit = {}, + onCardClick: (Long) -> Unit = {}, + modifier: Modifier = Modifier, +) { + // TODO: [예림] ViewModel 연결되면 교체 + val uiState = HistoryListUiState( + selectedTab = PotiHeaderTabType.ONGOING, + ongoingCount = 2, + endedCount = 5, + items = listOf( + HistoryItem( + id = 1L, + imageUrl = "", + artist = "ive(아이브)", + title = "러브다이브 위드뮤", + stageType = ParticipantStateLabelStage.DELIVERY, + statusType = ParticipantStateLabelStatus.WAIT, + ), + HistoryItem( + id = 2L, + imageUrl = "", + artist = "aespa", + title = "걸스 스페셜", + stageType = ParticipantStateLabelStage.DEPOSIT, + statusType = ParticipantStateLabelStatus.DONE, + ), + ), + ) + + HistoryListScreen( + uiState = uiState, + onBackClick = onBackClick, + onSwitchModeClick = onSwitchModeClick, + onTabSelected = onTabSelected, + onCardClick = onCardClick, modifier = modifier, ) } + +@Composable +private fun HistoryListScreen( + uiState: HistoryListUiState, + onBackClick: () -> Unit, + onSwitchModeClick: () -> Unit, + onTabSelected: (PotiHeaderTabType) -> Unit, + onCardClick: (Long) -> Unit, + modifier: Modifier = Modifier, +) { + val titleRes = when (uiState.mode) { + HistoryMode.RECRUIT -> R.string.user_history_recruit + HistoryMode.PARTICIPATION -> R.string.user_history_participate + } + + Scaffold( + topBar = { + PotiHeaderPage( + onNavigationClick = onBackClick, + title = stringResource(titleRes), + onTrailingIconClick = onSwitchModeClick, + ) + }, + ) { innerPadding -> + Column( + modifier = modifier + .fillMaxSize() + .padding(innerPadding), + ) { + PotiHeaderSection( + selectedTab = uiState.selectedTab, + ongoingCount = uiState.ongoingCount, + endedCount = uiState.endedCount, + onTabSelected = onTabSelected, + ) + + LazyColumn( + modifier = Modifier.fillMaxSize(), + contentPadding = androidx.compose.foundation.layout.PaddingValues( + horizontal = 16.dp, + vertical = 12.dp, + ), + verticalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(10.dp), + ) { + items( + items = uiState.items, + key = { it.id }, + ) { item -> + + HistoryCardItem( + sizeType = CardHistorySize.SMALL, + imageUrl = item.imageUrl, + artist = item.artist, + title = item.title, + participantStageType = item.stageType, + participantStatusType = item.statusType, + onClick = { onCardClick(item.id) }, + ) + } + } + } + } +} + +@Preview(showBackground = true) +@Composable +private fun HistoryListScreenPreview_Ongoing() { + PotiTheme { + HistoryListScreen( + uiState = HistoryListUiState( + selectedTab = PotiHeaderTabType.ONGOING, + ongoingCount = 2, + endedCount = 5, + items = listOf( + HistoryItem( + id = 1L, + imageUrl = "", + artist = "ive(아이브)", + title = "러브다이브 위드뮤", + stageType = ParticipantStateLabelStage.DELIVERY, + statusType = ParticipantStateLabelStatus.WAIT, + ), + HistoryItem( + id = 2L, + imageUrl = "", + artist = "aespa", + title = "걸스 스페셜", + stageType = ParticipantStateLabelStage.DEPOSIT, + statusType = ParticipantStateLabelStatus.DONE, + ), + ), + ), + onBackClick = {}, + onSwitchModeClick = {}, + onTabSelected = {}, + onCardClick = {}, + ) + } +} + +@Preview(showBackground = true) +@Composable +private fun HistoryListScreenPreview_Ended() { + PotiTheme { + HistoryListScreen( + uiState = HistoryListUiState( + selectedTab = PotiHeaderTabType.ENDED, + ongoingCount = 2, + endedCount = 5, + items = listOf( + HistoryItem( + id = 3L, + imageUrl = "", + artist = "ive(아이브)", + title = "러브다이브 위드뮤", + stageType = ParticipantStateLabelStage.DELIVERY, + statusType = ParticipantStateLabelStatus.DONE, + ), + ), + ), + onBackClick = {}, + onSwitchModeClick = {}, + onTabSelected = {}, + onCardClick = {}, + ) + } +} diff --git a/app/src/main/java/com/poti/android/presentation/history/list/model/HistoryListUiState.kt b/app/src/main/java/com/poti/android/presentation/history/list/model/HistoryListUiState.kt new file mode 100644 index 00000000..4c937135 --- /dev/null +++ b/app/src/main/java/com/poti/android/presentation/history/list/model/HistoryListUiState.kt @@ -0,0 +1,24 @@ +package com.poti.android.presentation.history.list.model + +import com.poti.android.core.designsystem.component.navigation.PotiHeaderTabType +import com.poti.android.presentation.history.component.ParticipantStateLabelStage +import com.poti.android.presentation.history.component.ParticipantStateLabelStatus +import com.poti.android.presentation.history.list.HistoryMode + +data class HistoryListUiState( + val isLoading: Boolean = false, + val mode: HistoryMode = HistoryMode.RECRUIT, + val selectedTab: PotiHeaderTabType = PotiHeaderTabType.ONGOING, + val ongoingCount: Int = 0, + val endedCount: Int = 0, + val items: List = emptyList(), +) + +data class HistoryItem( + val id: Long, + val imageUrl: String, + val artist: String, + val title: String, + val stageType: ParticipantStateLabelStage, + val statusType: ParticipantStateLabelStatus, +) From e55458db098f03a04bb23045dfeccd447af8cd3e Mon Sep 17 00:00:00 2001 From: Yerim Son Date: Sun, 18 Jan 2026 15:20:33 +0900 Subject: [PATCH 2/8] [Feat/#56] HistoryListViewModel --- .../history/list/HistoryListScreen.kt | 75 +++++++------ .../history/list/HistoryListViewModel.kt | 100 +++++++++++++++++- .../{HistoryListUiState.kt => Contracts.kt} | 23 +++- .../history/navigation/HistoryNavigation.kt | 9 +- .../android/presentation/main/PotiNavHost.kt | 2 + 5 files changed, 170 insertions(+), 39 deletions(-) rename app/src/main/java/com/poti/android/presentation/history/list/model/{HistoryListUiState.kt => Contracts.kt} (55%) diff --git a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt index 82cf025e..6c614bff 100644 --- a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt +++ b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt @@ -1,17 +1,23 @@ package com.poti.android.presentation.history.list +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.poti.android.R +import com.poti.android.core.common.util.HandleSideEffects import com.poti.android.core.designsystem.component.navigation.PotiHeaderPage import com.poti.android.core.designsystem.component.navigation.PotiHeaderSection import com.poti.android.core.designsystem.component.navigation.PotiHeaderTabType @@ -21,6 +27,8 @@ import com.poti.android.presentation.history.component.HistoryCardItem import com.poti.android.presentation.history.component.ParticipantStateLabelStage import com.poti.android.presentation.history.component.ParticipantStateLabelStatus import com.poti.android.presentation.history.list.model.HistoryItem +import com.poti.android.presentation.history.list.model.HistoryListUiEffect +import com.poti.android.presentation.history.list.model.HistoryListUiIntent import com.poti.android.presentation.history.list.model.HistoryListUiState enum class HistoryMode { @@ -30,43 +38,39 @@ enum class HistoryMode { @Composable fun HistoryListRoute( - onBackClick: () -> Unit = {}, - onSwitchModeClick: () -> Unit = {}, - onTabSelected: (PotiHeaderTabType) -> Unit = {}, - onCardClick: (Long) -> Unit = {}, + onPopBackStack: () -> Unit, + onNavigateToRecruiterDetail: () -> Unit, + onNavigateToParticipantDetail: () -> Unit, modifier: Modifier = Modifier, + viewModel: HistoryListViewModel = hiltViewModel(), ) { - // TODO: [예림] ViewModel 연결되면 교체 - val uiState = HistoryListUiState( - selectedTab = PotiHeaderTabType.ONGOING, - ongoingCount = 2, - endedCount = 5, - items = listOf( - HistoryItem( - id = 1L, - imageUrl = "", - artist = "ive(아이브)", - title = "러브다이브 위드뮤", - stageType = ParticipantStateLabelStage.DELIVERY, - statusType = ParticipantStateLabelStatus.WAIT, - ), - HistoryItem( - id = 2L, - imageUrl = "", - artist = "aespa", - title = "걸스 스페셜", - stageType = ParticipantStateLabelStage.DEPOSIT, - statusType = ParticipantStateLabelStatus.DONE, - ), - ), - ) + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + + HandleSideEffects(viewModel.sideEffect) { effect -> + when (effect) { + HistoryListUiEffect.NavigateBack -> onPopBackStack() + is HistoryListUiEffect.NavigateToDetail -> { + // TODO: [예림] effect.id 전달 + if (uiState.mode == HistoryMode.RECRUIT) { + onNavigateToRecruiterDetail() + } else { + onNavigateToParticipantDetail() + } + } + is HistoryListUiEffect.SwitchMode -> {} + } + } HistoryListScreen( uiState = uiState, - onBackClick = onBackClick, - onSwitchModeClick = onSwitchModeClick, - onTabSelected = onTabSelected, - onCardClick = onCardClick, + onBackClick = { viewModel.processIntent(HistoryListUiIntent.OnBackClick) }, + onSwitchModeClick = { viewModel.processIntent(HistoryListUiIntent.OnSwitchModeClick) }, + onTabSelected = { tab -> + viewModel.processIntent(HistoryListUiIntent.OnTabSelected(tab)) + }, + onCardClick = { id -> + viewModel.processIntent(HistoryListUiIntent.OnCardClick(id)) + }, modifier = modifier, ) } @@ -86,6 +90,7 @@ private fun HistoryListScreen( } Scaffold( + modifier = modifier, topBar = { PotiHeaderPage( onNavigationClick = onBackClick, @@ -95,7 +100,7 @@ private fun HistoryListScreen( }, ) { innerPadding -> Column( - modifier = modifier + modifier = Modifier .fillMaxSize() .padding(innerPadding), ) { @@ -108,11 +113,11 @@ private fun HistoryListScreen( LazyColumn( modifier = Modifier.fillMaxSize(), - contentPadding = androidx.compose.foundation.layout.PaddingValues( + contentPadding = PaddingValues( horizontal = 16.dp, vertical = 12.dp, ), - verticalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(10.dp), + verticalArrangement = Arrangement.spacedBy(10.dp), ) { items( items = uiState.items, diff --git a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt index 0b169496..f039b9b4 100644 --- a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt +++ b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt @@ -1,9 +1,105 @@ package com.poti.android.presentation.history.list -import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.poti.android.core.base.BaseViewModel +import com.poti.android.core.designsystem.component.navigation.PotiHeaderTabType +import com.poti.android.presentation.history.component.ParticipantStateLabelStage +import com.poti.android.presentation.history.component.ParticipantStateLabelStatus +import com.poti.android.presentation.history.list.model.HistoryItem +import com.poti.android.presentation.history.list.model.HistoryListUiEffect +import com.poti.android.presentation.history.list.model.HistoryListUiIntent +import com.poti.android.presentation.history.list.model.HistoryListUiState import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel -class HistoryListViewModel @Inject constructor() : ViewModel() { +class HistoryListViewModel @Inject constructor() : BaseViewModel( + initialState = HistoryListUiState(), +) { + override fun processIntent(intent: HistoryListUiIntent) { + when (intent) { + HistoryListUiIntent.OnBackClick -> sendEffect(HistoryListUiEffect.NavigateBack) + HistoryListUiIntent.OnSwitchModeClick -> { + val newMode = if (uiState.value.mode == HistoryMode.RECRUIT) { + HistoryMode.PARTICIPATION + } else { + HistoryMode.RECRUIT + } + updateState { + copy( + mode = newMode, + selectedTab = PotiHeaderTabType.ONGOING, + ) + } + sendEffect( + HistoryListUiEffect.SwitchMode(newMode == HistoryMode.RECRUIT), + ) + loadHistory() + } + is HistoryListUiIntent.OnTabSelected -> { + updateState { copy(selectedTab = intent.tab) } + loadHistory() + } + is HistoryListUiIntent.OnCardClick -> { + sendEffect(HistoryListUiEffect.NavigateToDetail(intent.id)) + } + } + } + + init { + loadHistory() + } + + private fun loadHistory() { + viewModelScope.launch { + updateState { copy(isLoading = true) } + + // TODO: [예림] API 분기 + // mode == RECRUIT -> 모집내역 API + // mode == PARTICIPATION -> 참여내역 API + // selectedTab -> IN_PROGRESS / COMPLETED + + val dummyItems = if (uiState.value.selectedTab == PotiHeaderTabType.ONGOING) { + listOf( + HistoryItem( + id = 1L, + imageUrl = "", + artist = "ive(아이브)", + title = "러브다이브 위드뮤", + stageType = ParticipantStateLabelStage.DELIVERY, + statusType = ParticipantStateLabelStatus.WAIT, + ), + HistoryItem( + id = 2L, + imageUrl = "", + artist = "aespa", + title = "걸스 스페셜", + stageType = ParticipantStateLabelStage.DEPOSIT, + statusType = ParticipantStateLabelStatus.DONE, + ), + ) + } else { + listOf( + HistoryItem( + id = 3L, + imageUrl = "", + artist = "ive(아이브)", + title = "러브다이브 위드뮤", + stageType = ParticipantStateLabelStage.DELIVERY, + statusType = ParticipantStateLabelStatus.DONE, + ), + ) + } + + updateState { + copy( + isLoading = false, + ongoingCount = 2, + endedCount = 5, + items = dummyItems, + ) + } + } + } } diff --git a/app/src/main/java/com/poti/android/presentation/history/list/model/HistoryListUiState.kt b/app/src/main/java/com/poti/android/presentation/history/list/model/Contracts.kt similarity index 55% rename from app/src/main/java/com/poti/android/presentation/history/list/model/HistoryListUiState.kt rename to app/src/main/java/com/poti/android/presentation/history/list/model/Contracts.kt index 4c937135..e19d214d 100644 --- a/app/src/main/java/com/poti/android/presentation/history/list/model/HistoryListUiState.kt +++ b/app/src/main/java/com/poti/android/presentation/history/list/model/Contracts.kt @@ -1,5 +1,8 @@ package com.poti.android.presentation.history.list.model +import com.poti.android.core.base.UiEffect +import com.poti.android.core.base.UiIntent +import com.poti.android.core.base.UiState import com.poti.android.core.designsystem.component.navigation.PotiHeaderTabType import com.poti.android.presentation.history.component.ParticipantStateLabelStage import com.poti.android.presentation.history.component.ParticipantStateLabelStatus @@ -12,7 +15,7 @@ data class HistoryListUiState( val ongoingCount: Int = 0, val endedCount: Int = 0, val items: List = emptyList(), -) +) : UiState data class HistoryItem( val id: Long, @@ -22,3 +25,21 @@ data class HistoryItem( val stageType: ParticipantStateLabelStage, val statusType: ParticipantStateLabelStatus, ) + +sealed interface HistoryListUiIntent : UiIntent { + data object OnBackClick : HistoryListUiIntent + + data object OnSwitchModeClick : HistoryListUiIntent + + data class OnTabSelected(val tab: PotiHeaderTabType) : HistoryListUiIntent + + data class OnCardClick(val id: Long) : HistoryListUiIntent +} + +sealed interface HistoryListUiEffect : UiEffect { + data object NavigateBack : HistoryListUiEffect + + data class SwitchMode(val isRecruitMode: Boolean) : HistoryListUiEffect + + data class NavigateToDetail(val id: Long) : HistoryListUiEffect +} diff --git a/app/src/main/java/com/poti/android/presentation/history/navigation/HistoryNavigation.kt b/app/src/main/java/com/poti/android/presentation/history/navigation/HistoryNavigation.kt index b3872c74..d3c54a59 100644 --- a/app/src/main/java/com/poti/android/presentation/history/navigation/HistoryNavigation.kt +++ b/app/src/main/java/com/poti/android/presentation/history/navigation/HistoryNavigation.kt @@ -44,10 +44,17 @@ fun NavController.navigateToParticipantManage() { } fun NavGraphBuilder.historyNavGraph( + navController: NavController, paddingValues: PaddingValues, + onPopBackStack: () -> Unit, ) { composable { - HistoryListRoute(modifier = Modifier.padding(paddingValues)) + HistoryListRoute( + onPopBackStack = onPopBackStack, + onNavigateToRecruiterDetail = navController::navigateToRecruiterDetail, + onNavigateToParticipantDetail = navController::navigateToParticipantDetail, + modifier = Modifier.padding(paddingValues), + ) } composable { ParticipantDetailRoute(modifier = Modifier.padding(paddingValues)) diff --git a/app/src/main/java/com/poti/android/presentation/main/PotiNavHost.kt b/app/src/main/java/com/poti/android/presentation/main/PotiNavHost.kt index 6aae53d1..5f5a68d1 100644 --- a/app/src/main/java/com/poti/android/presentation/main/PotiNavHost.kt +++ b/app/src/main/java/com/poti/android/presentation/main/PotiNavHost.kt @@ -36,7 +36,9 @@ fun PotiNavHost( paddingValues = paddingValues, ) historyNavGraph( + navController = navigator.navController, paddingValues = paddingValues, + onPopBackStack = navigator.navController::popBackStack, ) myPageNavGraph( paddingValues = paddingValues, From 56b7f2cf5adb6e187d7f28625e00019149c52c7a Mon Sep 17 00:00:00 2001 From: Yerim Son Date: Sun, 18 Jan 2026 15:38:43 +0900 Subject: [PATCH 3/8] =?UTF-8?q?[Feat/#56]=20=EB=82=B4=EC=97=AD=20=EC=97=86?= =?UTF-8?q?=EC=9D=84=20=EB=95=8C=20Empty=20State=20UI=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../history/list/HistoryListScreen.kt | 89 ++++++++++++------- .../history/list/HistoryListViewModel.kt | 13 +-- app/src/main/res/values/strings.xml | 6 ++ 3 files changed, 65 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt index 6c614bff..43419a41 100644 --- a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt +++ b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt @@ -4,12 +4,14 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -18,6 +20,8 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.poti.android.R import com.poti.android.core.common.util.HandleSideEffects +import com.poti.android.core.common.util.screenHeightDp +import com.poti.android.core.designsystem.component.display.PotiEmptyStateBlock import com.poti.android.core.designsystem.component.navigation.PotiHeaderPage import com.poti.android.core.designsystem.component.navigation.PotiHeaderSection import com.poti.android.core.designsystem.component.navigation.PotiHeaderTabType @@ -89,6 +93,22 @@ private fun HistoryListScreen( HistoryMode.PARTICIPATION -> R.string.user_history_participate } + val emptyTextRes = when (uiState.mode) { + HistoryMode.RECRUIT -> { + when (uiState.selectedTab) { + PotiHeaderTabType.ONGOING -> R.string.history_empty_recruit_ongoing + PotiHeaderTabType.ENDED -> R.string.history_empty_recruit_ended + } + } + + HistoryMode.PARTICIPATION -> { + when (uiState.selectedTab) { + PotiHeaderTabType.ONGOING -> R.string.history_empty_participation_ongoing + PotiHeaderTabType.ENDED -> R.string.history_empty_participation_ended + } + } + } + Scaffold( modifier = modifier, topBar = { @@ -111,29 +131,43 @@ private fun HistoryListScreen( onTabSelected = onTabSelected, ) - LazyColumn( - modifier = Modifier.fillMaxSize(), - contentPadding = PaddingValues( - horizontal = 16.dp, - vertical = 12.dp, - ), - verticalArrangement = Arrangement.spacedBy(10.dp), - ) { - items( - items = uiState.items, - key = { it.id }, - ) { item -> - - HistoryCardItem( - sizeType = CardHistorySize.SMALL, - imageUrl = item.imageUrl, - artist = item.artist, - title = item.title, - participantStageType = item.stageType, - participantStatusType = item.statusType, - onClick = { onCardClick(item.id) }, + if (uiState.items.isEmpty()) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(top = screenHeightDp(64.dp)), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + PotiEmptyStateBlock( + text = stringResource(emptyTextRes), ) } + } else { + LazyColumn( + modifier = Modifier.fillMaxSize(), + contentPadding = PaddingValues( + horizontal = 16.dp, + vertical = 12.dp, + ), + verticalArrangement = Arrangement.spacedBy(10.dp), + ) { + items( + items = uiState.items, + key = { it.id }, + ) { item -> + + HistoryCardItem( + sizeType = CardHistorySize.SMALL, + imageUrl = item.imageUrl, + artist = item.artist, + title = item.title, + participantStageType = item.stageType, + participantStatusType = item.statusType, + onClick = { onCardClick(item.id) }, + ) + } + } } } } @@ -183,17 +217,8 @@ private fun HistoryListScreenPreview_Ended() { uiState = HistoryListUiState( selectedTab = PotiHeaderTabType.ENDED, ongoingCount = 2, - endedCount = 5, - items = listOf( - HistoryItem( - id = 3L, - imageUrl = "", - artist = "ive(아이브)", - title = "러브다이브 위드뮤", - stageType = ParticipantStateLabelStage.DELIVERY, - statusType = ParticipantStateLabelStatus.DONE, - ), - ), + endedCount = 0, + items = listOf(), ), onBackClick = {}, onSwitchModeClick = {}, diff --git a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt index f039b9b4..eccac91e 100644 --- a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt +++ b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt @@ -80,23 +80,14 @@ class HistoryListViewModel @Inject constructor() : BaseViewModel진행중 종료 + + 진행 중인 모집 내역이 없어요 + 지난 모집 내역이 없어요 + 진행 중인 참여 내역이 없어요 + 지난 참여 내역이 없어요 + From a6817c5064ab93860e83c53456314cf4b2240f7e Mon Sep 17 00:00:00 2001 From: Yerim Son Date: Sun, 18 Jan 2026 16:14:30 +0900 Subject: [PATCH 4/8] =?UTF-8?q?[Fix/#56]=20PotiEmptyStateBlock=EC=9D=84=20?= =?UTF-8?q?PotiEmptyStateInline=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../history/list/HistoryListScreen.kt | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt index 43419a41..013eeb07 100644 --- a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt +++ b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt @@ -11,7 +11,6 @@ import androidx.compose.foundation.lazy.items import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -20,8 +19,7 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.poti.android.R import com.poti.android.core.common.util.HandleSideEffects -import com.poti.android.core.common.util.screenHeightDp -import com.poti.android.core.designsystem.component.display.PotiEmptyStateBlock +import com.poti.android.core.designsystem.component.display.PotiEmptyStateInline import com.poti.android.core.designsystem.component.navigation.PotiHeaderPage import com.poti.android.core.designsystem.component.navigation.PotiHeaderSection import com.poti.android.core.designsystem.component.navigation.PotiHeaderTabType @@ -132,17 +130,10 @@ private fun HistoryListScreen( ) if (uiState.items.isEmpty()) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(top = screenHeightDp(64.dp)), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center, - ) { - PotiEmptyStateBlock( - text = stringResource(emptyTextRes), - ) - } + PotiEmptyStateInline( + text = stringResource(emptyTextRes), + modifier = Modifier.fillMaxWidth(), + ) } else { LazyColumn( modifier = Modifier.fillMaxSize(), From 81e988e14caba580586dfd40b2e029052376b821 Mon Sep 17 00:00:00 2001 From: Yerim Son Date: Mon, 19 Jan 2026 07:53:47 +0900 Subject: [PATCH 5/8] =?UTF-8?q?[Refactor/#56]=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../history/list/HistoryListScreen.kt | 27 ++----------------- .../history/list/HistoryListViewModel.kt | 3 --- .../history/list/model/Contracts.kt | 26 +++++++++++++++--- 3 files changed, 25 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt index 013eeb07..bae3f4bc 100644 --- a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt +++ b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt @@ -17,7 +17,6 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.poti.android.R import com.poti.android.core.common.util.HandleSideEffects import com.poti.android.core.designsystem.component.display.PotiEmptyStateInline import com.poti.android.core.designsystem.component.navigation.PotiHeaderPage @@ -59,7 +58,6 @@ fun HistoryListRoute( onNavigateToParticipantDetail() } } - is HistoryListUiEffect.SwitchMode -> {} } } @@ -86,33 +84,12 @@ private fun HistoryListScreen( onCardClick: (Long) -> Unit, modifier: Modifier = Modifier, ) { - val titleRes = when (uiState.mode) { - HistoryMode.RECRUIT -> R.string.user_history_recruit - HistoryMode.PARTICIPATION -> R.string.user_history_participate - } - - val emptyTextRes = when (uiState.mode) { - HistoryMode.RECRUIT -> { - when (uiState.selectedTab) { - PotiHeaderTabType.ONGOING -> R.string.history_empty_recruit_ongoing - PotiHeaderTabType.ENDED -> R.string.history_empty_recruit_ended - } - } - - HistoryMode.PARTICIPATION -> { - when (uiState.selectedTab) { - PotiHeaderTabType.ONGOING -> R.string.history_empty_participation_ongoing - PotiHeaderTabType.ENDED -> R.string.history_empty_participation_ended - } - } - } - Scaffold( modifier = modifier, topBar = { PotiHeaderPage( onNavigationClick = onBackClick, - title = stringResource(titleRes), + title = stringResource(uiState.titleRes), onTrailingIconClick = onSwitchModeClick, ) }, @@ -131,7 +108,7 @@ private fun HistoryListScreen( if (uiState.items.isEmpty()) { PotiEmptyStateInline( - text = stringResource(emptyTextRes), + text = stringResource(uiState.emptyTextRes), modifier = Modifier.fillMaxWidth(), ) } else { diff --git a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt index eccac91e..1fb7292d 100644 --- a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt +++ b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt @@ -32,9 +32,6 @@ class HistoryListViewModel @Inject constructor() : BaseViewModel { diff --git a/app/src/main/java/com/poti/android/presentation/history/list/model/Contracts.kt b/app/src/main/java/com/poti/android/presentation/history/list/model/Contracts.kt index e19d214d..50abbcae 100644 --- a/app/src/main/java/com/poti/android/presentation/history/list/model/Contracts.kt +++ b/app/src/main/java/com/poti/android/presentation/history/list/model/Contracts.kt @@ -1,5 +1,6 @@ package com.poti.android.presentation.history.list.model +import com.poti.android.R import com.poti.android.core.base.UiEffect import com.poti.android.core.base.UiIntent import com.poti.android.core.base.UiState @@ -15,7 +16,28 @@ data class HistoryListUiState( val ongoingCount: Int = 0, val endedCount: Int = 0, val items: List = emptyList(), -) : UiState +) : UiState { + val titleRes = when (mode) { + HistoryMode.RECRUIT -> R.string.user_history_recruit + HistoryMode.PARTICIPATION -> R.string.user_history_participate + } + + val emptyTextRes = when (mode) { + HistoryMode.RECRUIT -> { + when (selectedTab) { + PotiHeaderTabType.ONGOING -> R.string.history_empty_recruit_ongoing + PotiHeaderTabType.ENDED -> R.string.history_empty_recruit_ended + } + } + + HistoryMode.PARTICIPATION -> { + when (selectedTab) { + PotiHeaderTabType.ONGOING -> R.string.history_empty_participation_ongoing + PotiHeaderTabType.ENDED -> R.string.history_empty_participation_ended + } + } + } +} data class HistoryItem( val id: Long, @@ -39,7 +61,5 @@ sealed interface HistoryListUiIntent : UiIntent { sealed interface HistoryListUiEffect : UiEffect { data object NavigateBack : HistoryListUiEffect - data class SwitchMode(val isRecruitMode: Boolean) : HistoryListUiEffect - data class NavigateToDetail(val id: Long) : HistoryListUiEffect } From 4181c3638178f80da11ff77f3a94a5fd5e059ddd Mon Sep 17 00:00:00 2001 From: Yerim Son Date: Tue, 20 Jan 2026 08:22:47 +0900 Subject: [PATCH 6/8] =?UTF-8?q?[Refactor/#56]=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/model/history/HistoryList.kt | 19 ++++ .../history/list/HistoryListScreen.kt | 62 +++++++----- .../history/list/HistoryListViewModel.kt | 96 ++++++++++++------- .../history/list/model/Contracts.kt | 27 +++--- app/src/main/res/values/strings.xml | 2 + 5 files changed, 128 insertions(+), 78 deletions(-) create mode 100644 app/src/main/java/com/poti/android/domain/model/history/HistoryList.kt diff --git a/app/src/main/java/com/poti/android/domain/model/history/HistoryList.kt b/app/src/main/java/com/poti/android/domain/model/history/HistoryList.kt new file mode 100644 index 00000000..329369ad --- /dev/null +++ b/app/src/main/java/com/poti/android/domain/model/history/HistoryList.kt @@ -0,0 +1,19 @@ +package com.poti.android.domain.model.history + +import com.poti.android.presentation.history.component.ParticipantStateLabelStage +import com.poti.android.presentation.history.component.ParticipantStateLabelStatus + +data class HistoryListContent( + val ongoingCount: Int, + val endedCount: Int, + val items: List, +) + +data class HistoryItem( + val id: Long, + val imageUrl: String?, + val artist: String, + val title: String, + val stage: ParticipantStateLabelStage, + val status: ParticipantStateLabelStatus, +) diff --git a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt index bae3f4bc..d67c06b5 100644 --- a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt +++ b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt @@ -17,17 +17,19 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.poti.android.core.common.state.ApiState import com.poti.android.core.common.util.HandleSideEffects import com.poti.android.core.designsystem.component.display.PotiEmptyStateInline import com.poti.android.core.designsystem.component.navigation.PotiHeaderPage import com.poti.android.core.designsystem.component.navigation.PotiHeaderSection import com.poti.android.core.designsystem.component.navigation.PotiHeaderTabType import com.poti.android.core.designsystem.theme.PotiTheme +import com.poti.android.domain.model.history.HistoryItem +import com.poti.android.domain.model.history.HistoryListContent import com.poti.android.presentation.history.component.CardHistorySize import com.poti.android.presentation.history.component.HistoryCardItem import com.poti.android.presentation.history.component.ParticipantStateLabelStage import com.poti.android.presentation.history.component.ParticipantStateLabelStatus -import com.poti.android.presentation.history.list.model.HistoryItem import com.poti.android.presentation.history.list.model.HistoryListUiEffect import com.poti.android.presentation.history.list.model.HistoryListUiIntent import com.poti.android.presentation.history.list.model.HistoryListUiState @@ -127,11 +129,11 @@ private fun HistoryListScreen( HistoryCardItem( sizeType = CardHistorySize.SMALL, - imageUrl = item.imageUrl, + imageUrl = item.imageUrl ?: "", artist = item.artist, title = item.title, - participantStageType = item.stageType, - participantStatusType = item.statusType, + participantStageType = item.stage, + participantStatusType = item.status, onClick = { onCardClick(item.id) }, ) } @@ -147,27 +149,31 @@ private fun HistoryListScreenPreview_Ongoing() { PotiTheme { HistoryListScreen( uiState = HistoryListUiState( - selectedTab = PotiHeaderTabType.ONGOING, - ongoingCount = 2, - endedCount = 5, - items = listOf( - HistoryItem( - id = 1L, - imageUrl = "", - artist = "ive(아이브)", - title = "러브다이브 위드뮤", - stageType = ParticipantStateLabelStage.DELIVERY, - statusType = ParticipantStateLabelStatus.WAIT, - ), - HistoryItem( - id = 2L, - imageUrl = "", - artist = "aespa", - title = "걸스 스페셜", - stageType = ParticipantStateLabelStage.DEPOSIT, - statusType = ParticipantStateLabelStatus.DONE, + historyListLoadState = ApiState.Success( + HistoryListContent( + ongoingCount = 2, + endedCount = 5, + items = listOf( + HistoryItem( + id = 1L, + imageUrl = "", + artist = "ive(아이브)", + title = "러브다이브 위드뮤", + stage = ParticipantStateLabelStage.DELIVERY, + status = ParticipantStateLabelStatus.WAIT, + ), + HistoryItem( + id = 2L, + imageUrl = "", + artist = "aespa", + title = "걸스 스페셜", + stage = ParticipantStateLabelStage.DEPOSIT, + status = ParticipantStateLabelStatus.DONE, + ), + ), ), ), + selectedTab = PotiHeaderTabType.ONGOING, ), onBackClick = {}, onSwitchModeClick = {}, @@ -183,10 +189,14 @@ private fun HistoryListScreenPreview_Ended() { PotiTheme { HistoryListScreen( uiState = HistoryListUiState( + historyListLoadState = ApiState.Success( + HistoryListContent( + ongoingCount = 2, + endedCount = 0, + items = emptyList(), + ), + ), selectedTab = PotiHeaderTabType.ENDED, - ongoingCount = 2, - endedCount = 0, - items = listOf(), ), onBackClick = {}, onSwitchModeClick = {}, diff --git a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt index 1fb7292d..a3ef56f0 100644 --- a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt +++ b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt @@ -2,14 +2,17 @@ package com.poti.android.presentation.history.list import androidx.lifecycle.viewModelScope import com.poti.android.core.base.BaseViewModel +import com.poti.android.core.common.state.ApiState import com.poti.android.core.designsystem.component.navigation.PotiHeaderTabType +import com.poti.android.domain.model.history.HistoryItem +import com.poti.android.domain.model.history.HistoryListContent import com.poti.android.presentation.history.component.ParticipantStateLabelStage import com.poti.android.presentation.history.component.ParticipantStateLabelStatus -import com.poti.android.presentation.history.list.model.HistoryItem import com.poti.android.presentation.history.list.model.HistoryListUiEffect import com.poti.android.presentation.history.list.model.HistoryListUiIntent import com.poti.android.presentation.history.list.model.HistoryListUiState import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Job import kotlinx.coroutines.launch import javax.inject.Inject @@ -32,11 +35,11 @@ class HistoryListViewModel @Inject constructor() : BaseViewModel { updateState { copy(selectedTab = intent.tab) } - loadHistory() + loadUserHistoryList() } is HistoryListUiIntent.OnCardClick -> { sendEffect(HistoryListUiEffect.NavigateToDetail(intent.id)) @@ -45,49 +48,68 @@ class HistoryListViewModel @Inject constructor() : BaseViewModel 모집내역 API - // mode == PARTICIPATION -> 참여내역 API - // selectedTab -> IN_PROGRESS / COMPLETED + private fun loadUserHistoryList() { + fetchJob?.cancel() - val dummyItems = if (uiState.value.selectedTab == PotiHeaderTabType.ONGOING) { - listOf( - HistoryItem( - id = 1L, - imageUrl = "", - artist = "ive(아이브)", - title = "러브다이브 위드뮤", - stageType = ParticipantStateLabelStage.DELIVERY, - statusType = ParticipantStateLabelStatus.WAIT, - ), - HistoryItem( - id = 2L, - imageUrl = "", - artist = "aespa", - title = "걸스 스페셜", - stageType = ParticipantStateLabelStage.DEPOSIT, - statusType = ParticipantStateLabelStatus.DONE, - ), - ) - } else { - listOf() - } + fetchJob = viewModelScope.launch { + val dummyContent = createDummyContent() updateState { copy( - isLoading = false, - ongoingCount = 2, - endedCount = 0, - items = dummyItems, + historyListLoadState = ApiState.Success(dummyContent), ) } } } + + fun createDummyContent(): HistoryListContent { + val isOngoing = uiState.value.selectedTab == PotiHeaderTabType.ONGOING + val isRecruit = uiState.value.mode == HistoryMode.RECRUIT + + val ongoingItems = listOf( + HistoryItem( + id = 1L, + imageUrl = "", + artist = if (isRecruit) "IVE" else "aespa", + title = if (isRecruit) "러브다이브 공동구매" else "걸스 앨범 분철", + stage = ParticipantStateLabelStage.DELIVERY, + status = ParticipantStateLabelStatus.WAIT, + ), + HistoryItem( + id = 2L, + imageUrl = "", + artist = "NewJeans", + title = "OMG 한정판", + stage = ParticipantStateLabelStage.DEPOSIT, + status = ParticipantStateLabelStatus.DONE, + ), + ) + + val endedItems = listOf( + HistoryItem( + id = 3L, + imageUrl = "", + artist = "LE SSERAFIM", + title = "ANTIFRAGILE", + stage = ParticipantStateLabelStage.DELIVERY, + status = ParticipantStateLabelStatus.DONE, + ), + ) + + return HistoryListContent( + ongoingCount = ongoingItems.size, + endedCount = endedItems.size, + items = if (isOngoing) ongoingItems else endedItems, + ) + } + + // TODO: [예림] API 분기 + // mode == RECRUIT -> 모집내역 API + // mode == PARTICIPATION -> 참여내역 API + // selectedTab -> IN_PROGRESS / COMPLETED } diff --git a/app/src/main/java/com/poti/android/presentation/history/list/model/Contracts.kt b/app/src/main/java/com/poti/android/presentation/history/list/model/Contracts.kt index 50abbcae..053c09b3 100644 --- a/app/src/main/java/com/poti/android/presentation/history/list/model/Contracts.kt +++ b/app/src/main/java/com/poti/android/presentation/history/list/model/Contracts.kt @@ -4,18 +4,16 @@ import com.poti.android.R import com.poti.android.core.base.UiEffect import com.poti.android.core.base.UiIntent import com.poti.android.core.base.UiState +import com.poti.android.core.common.state.ApiState import com.poti.android.core.designsystem.component.navigation.PotiHeaderTabType -import com.poti.android.presentation.history.component.ParticipantStateLabelStage -import com.poti.android.presentation.history.component.ParticipantStateLabelStatus +import com.poti.android.domain.model.history.HistoryItem +import com.poti.android.domain.model.history.HistoryListContent import com.poti.android.presentation.history.list.HistoryMode data class HistoryListUiState( - val isLoading: Boolean = false, + val historyListLoadState: ApiState = ApiState.Init, val mode: HistoryMode = HistoryMode.RECRUIT, val selectedTab: PotiHeaderTabType = PotiHeaderTabType.ONGOING, - val ongoingCount: Int = 0, - val endedCount: Int = 0, - val items: List = emptyList(), ) : UiState { val titleRes = when (mode) { HistoryMode.RECRUIT -> R.string.user_history_recruit @@ -37,16 +35,15 @@ data class HistoryListUiState( } } } -} + val items: List + get() = (historyListLoadState as? ApiState.Success)?.data?.items.orEmpty() + + val ongoingCount: Int + get() = (historyListLoadState as? ApiState.Success)?.data?.ongoingCount ?: 0 -data class HistoryItem( - val id: Long, - val imageUrl: String, - val artist: String, - val title: String, - val stageType: ParticipantStateLabelStage, - val statusType: ParticipantStateLabelStatus, -) + val endedCount: Int + get() = (historyListLoadState as? ApiState.Success)?.data?.endedCount ?: 0 +} sealed interface HistoryListUiIntent : UiIntent { data object OnBackClick : HistoryListUiIntent diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e965314c..3e995239 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -116,6 +116,8 @@ 전체 진행중 종료 + 마이 + 나의 최애 선택하기 진행 중인 모집 내역이 없어요 From 82e38b0d6228e8be085a381dc7f18adc57245c87 Mon Sep 17 00:00:00 2001 From: Yerim Son Date: Tue, 20 Jan 2026 16:32:34 +0900 Subject: [PATCH 7/8] =?UTF-8?q?[Refactor/#57]=20processIntent=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../history/list/HistoryListViewModel.kt | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt index a3ef56f0..cde45de5 100644 --- a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt +++ b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt @@ -23,24 +23,8 @@ class HistoryListViewModel @Inject constructor() : BaseViewModel sendEffect(HistoryListUiEffect.NavigateBack) - HistoryListUiIntent.OnSwitchModeClick -> { - val newMode = if (uiState.value.mode == HistoryMode.RECRUIT) { - HistoryMode.PARTICIPATION - } else { - HistoryMode.RECRUIT - } - updateState { - copy( - mode = newMode, - selectedTab = PotiHeaderTabType.ONGOING, - ) - } - loadUserHistoryList() - } - is HistoryListUiIntent.OnTabSelected -> { - updateState { copy(selectedTab = intent.tab) } - loadUserHistoryList() - } + HistoryListUiIntent.OnSwitchModeClick -> switchMode() + is HistoryListUiIntent.OnTabSelected -> selectTab(intent.tab) is HistoryListUiIntent.OnCardClick -> { sendEffect(HistoryListUiEffect.NavigateToDetail(intent.id)) } @@ -51,6 +35,28 @@ class HistoryListViewModel @Inject constructor() : BaseViewModel Date: Tue, 20 Jan 2026 16:54:26 +0900 Subject: [PATCH 8/8] =?UTF-8?q?[Refactor/#57]=20=ED=94=84=EB=A0=88?= =?UTF-8?q?=EC=A0=A0=ED=85=8C=EC=9D=B4=EC=85=98=20=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/model/history/HistoryList.kt | 8 ++++---- .../poti/android/domain/type/HistoryType.kt | 14 ++++++++++++++ .../history/list/HistoryListScreen.kt | 19 ++++++++++--------- .../history/list/HistoryListViewModel.kt | 16 ++++++++-------- .../history/list/model/Contracts.kt | 17 +++++++++++++++++ 5 files changed, 53 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/com/poti/android/domain/type/HistoryType.kt diff --git a/app/src/main/java/com/poti/android/domain/model/history/HistoryList.kt b/app/src/main/java/com/poti/android/domain/model/history/HistoryList.kt index 329369ad..3477fa5e 100644 --- a/app/src/main/java/com/poti/android/domain/model/history/HistoryList.kt +++ b/app/src/main/java/com/poti/android/domain/model/history/HistoryList.kt @@ -1,7 +1,7 @@ package com.poti.android.domain.model.history -import com.poti.android.presentation.history.component.ParticipantStateLabelStage -import com.poti.android.presentation.history.component.ParticipantStateLabelStatus +import com.poti.android.domain.type.HistoryStage +import com.poti.android.domain.type.HistoryStatus data class HistoryListContent( val ongoingCount: Int, @@ -14,6 +14,6 @@ data class HistoryItem( val imageUrl: String?, val artist: String, val title: String, - val stage: ParticipantStateLabelStage, - val status: ParticipantStateLabelStatus, + val stage: HistoryStage, + val status: HistoryStatus, ) diff --git a/app/src/main/java/com/poti/android/domain/type/HistoryType.kt b/app/src/main/java/com/poti/android/domain/type/HistoryType.kt new file mode 100644 index 00000000..8c83dcfc --- /dev/null +++ b/app/src/main/java/com/poti/android/domain/type/HistoryType.kt @@ -0,0 +1,14 @@ +package com.poti.android.domain.type + +enum class HistoryStage { + DEPOSIT, + DELIVERY, + RECRUIT, +} + +enum class HistoryStatus { + WAIT, + CHECK, + START, + DONE, +} diff --git a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt index d67c06b5..9e7a9067 100644 --- a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt +++ b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListScreen.kt @@ -26,13 +26,15 @@ import com.poti.android.core.designsystem.component.navigation.PotiHeaderTabType import com.poti.android.core.designsystem.theme.PotiTheme import com.poti.android.domain.model.history.HistoryItem import com.poti.android.domain.model.history.HistoryListContent +import com.poti.android.domain.type.HistoryStage +import com.poti.android.domain.type.HistoryStatus import com.poti.android.presentation.history.component.CardHistorySize import com.poti.android.presentation.history.component.HistoryCardItem -import com.poti.android.presentation.history.component.ParticipantStateLabelStage -import com.poti.android.presentation.history.component.ParticipantStateLabelStatus import com.poti.android.presentation.history.list.model.HistoryListUiEffect import com.poti.android.presentation.history.list.model.HistoryListUiIntent import com.poti.android.presentation.history.list.model.HistoryListUiState +import com.poti.android.presentation.history.list.model.toUiStage +import com.poti.android.presentation.history.list.model.toUiStatus enum class HistoryMode { RECRUIT, @@ -126,14 +128,13 @@ private fun HistoryListScreen( items = uiState.items, key = { it.id }, ) { item -> - HistoryCardItem( sizeType = CardHistorySize.SMALL, imageUrl = item.imageUrl ?: "", artist = item.artist, title = item.title, - participantStageType = item.stage, - participantStatusType = item.status, + participantStageType = item.toUiStage(), + participantStatusType = item.toUiStatus(), onClick = { onCardClick(item.id) }, ) } @@ -159,16 +160,16 @@ private fun HistoryListScreenPreview_Ongoing() { imageUrl = "", artist = "ive(아이브)", title = "러브다이브 위드뮤", - stage = ParticipantStateLabelStage.DELIVERY, - status = ParticipantStateLabelStatus.WAIT, + stage = HistoryStage.DELIVERY, + status = HistoryStatus.WAIT, ), HistoryItem( id = 2L, imageUrl = "", artist = "aespa", title = "걸스 스페셜", - stage = ParticipantStateLabelStage.DEPOSIT, - status = ParticipantStateLabelStatus.DONE, + stage = HistoryStage.DEPOSIT, + status = HistoryStatus.DONE, ), ), ), diff --git a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt index cde45de5..91069376 100644 --- a/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt +++ b/app/src/main/java/com/poti/android/presentation/history/list/HistoryListViewModel.kt @@ -6,8 +6,8 @@ import com.poti.android.core.common.state.ApiState import com.poti.android.core.designsystem.component.navigation.PotiHeaderTabType import com.poti.android.domain.model.history.HistoryItem import com.poti.android.domain.model.history.HistoryListContent -import com.poti.android.presentation.history.component.ParticipantStateLabelStage -import com.poti.android.presentation.history.component.ParticipantStateLabelStatus +import com.poti.android.domain.type.HistoryStage +import com.poti.android.domain.type.HistoryStatus import com.poti.android.presentation.history.list.model.HistoryListUiEffect import com.poti.android.presentation.history.list.model.HistoryListUiIntent import com.poti.android.presentation.history.list.model.HistoryListUiState @@ -83,16 +83,16 @@ class HistoryListViewModel @Inject constructor() : BaseViewModel ParticipantStateLabelStage.DEPOSIT + HistoryStage.DELIVERY -> ParticipantStateLabelStage.DELIVERY + HistoryStage.RECRUIT -> ParticipantStateLabelStage.RECRUIT +} + +fun HistoryItem.toUiStatus(): ParticipantStateLabelStatus = when (status) { + HistoryStatus.WAIT -> ParticipantStateLabelStatus.WAIT + HistoryStatus.CHECK -> ParticipantStateLabelStatus.CHECK + HistoryStatus.START -> ParticipantStateLabelStatus.START + HistoryStatus.DONE -> ParticipantStateLabelStatus.DONE +}