diff --git a/home/presentation/src/main/java/io/soma/cryptobook/home/presentation/HomeContract.kt b/home/presentation/src/main/java/io/soma/cryptobook/home/presentation/HomeContract.kt index 1f652b9..6ec0fcb 100644 --- a/home/presentation/src/main/java/io/soma/cryptobook/home/presentation/HomeContract.kt +++ b/home/presentation/src/main/java/io/soma/cryptobook/home/presentation/HomeContract.kt @@ -4,12 +4,15 @@ import io.soma.cryptobook.core.domain.model.CoinPriceVO import io.soma.cryptobook.core.presentation.Event import io.soma.cryptobook.core.presentation.SideEffect import io.soma.cryptobook.core.presentation.UiState +import io.soma.cryptobook.home.presentation.component.sortheader.SortDirection import java.math.BigDecimal data class HomeUiState( val coins: List = emptyList(), val isLoading: Boolean = false, val errorMsg: String? = null, + val sortField: SortField = SortField.Price, + val sortDirection: SortDirection = SortDirection.Desc, ) : UiState data class CoinItem( @@ -19,10 +22,17 @@ data class CoinItem( val priceChangePercentage24h: Double, ) +enum class SortField { + Symbol, + Price, + Change, +} + sealed interface HomeEvent : Event { data object OnRefresh : HomeEvent data object OnBackClicked : HomeEvent data class OnCoinClicked(val symbol: String) : HomeEvent + data class OnSortClicked(val field: SortField) : HomeEvent } sealed interface HomeSideEffect : SideEffect diff --git a/home/presentation/src/main/java/io/soma/cryptobook/home/presentation/HomeScreen.kt b/home/presentation/src/main/java/io/soma/cryptobook/home/presentation/HomeScreen.kt index 879b1d6..27493fe 100644 --- a/home/presentation/src/main/java/io/soma/cryptobook/home/presentation/HomeScreen.kt +++ b/home/presentation/src/main/java/io/soma/cryptobook/home/presentation/HomeScreen.kt @@ -64,14 +64,21 @@ internal fun HomeScreen(state: HomeUiState, onEvent: (HomeEvent) -> Unit, modifi } } - // Sort Header (TODO: 정렬 기능 구현) + // Sort Header + val symbolSort = + if (state.sortField == SortField.Symbol) state.sortDirection else SortDirection.None + val priceSort = + if (state.sortField == SortField.Price) state.sortDirection else SortDirection.None + val changeSort = + if (state.sortField == SortField.Change) state.sortDirection else SortDirection.None + SortHeader( - symbolSort = SortDirection.None, - priceSort = SortDirection.Desc, - changeSort = SortDirection.None, - onSymbolClick = { /* TODO: 정렬 기능 구현 */ }, - onPriceClick = { /* TODO: 정렬 기능 구현 */ }, - onChangeClick = { /* TODO: 정렬 기능 구현 */ }, + symbolSort = symbolSort, + priceSort = priceSort, + changeSort = changeSort, + onSymbolClick = { onEvent(HomeEvent.OnSortClicked(SortField.Symbol)) }, + onPriceClick = { onEvent(HomeEvent.OnSortClicked(SortField.Price)) }, + onChangeClick = { onEvent(HomeEvent.OnSortClicked(SortField.Change)) }, ) // Coin List diff --git a/home/presentation/src/main/java/io/soma/cryptobook/home/presentation/HomeViewModel.kt b/home/presentation/src/main/java/io/soma/cryptobook/home/presentation/HomeViewModel.kt index 0c743cd..92a8e5e 100644 --- a/home/presentation/src/main/java/io/soma/cryptobook/home/presentation/HomeViewModel.kt +++ b/home/presentation/src/main/java/io/soma/cryptobook/home/presentation/HomeViewModel.kt @@ -7,6 +7,7 @@ import io.soma.cryptobook.core.domain.navigation.AppPage import io.soma.cryptobook.core.domain.navigation.NavigationHelper import io.soma.cryptobook.core.presentation.MviViewModel import io.soma.cryptobook.home.domain.usecase.ObserveCoinListUseCase +import io.soma.cryptobook.home.presentation.component.sortheader.SortDirection import javax.inject.Inject @HiltViewModel @@ -31,6 +32,7 @@ class HomeViewModel @Inject constructor( is HomeEvent.OnCoinClicked -> navigationHelper.navigate( AppPage.CoinDetail(event.symbol), ) + is HomeEvent.OnSortClicked -> updateSort(event.field) } } @@ -39,11 +41,16 @@ class HomeViewModel @Inject constructor( observeCoinListUseCase().collect { result -> when (result) { is ObserveCoinListUseCase.Result.Success -> { + val sortedCoins = sortCoins( + coins = result.coinList.map { it.toCoinItem() }, + sortField = currentState.sortField, + sortDirection = currentState.sortDirection, + ) reduce { copy( isLoading = false, errorMsg = null, - coins = result.coinList.map { + coins = sortedCoins.coinList.map { it.toCoinItem(coinImageResolver.getImageUrl(it.symbol)) }, ) @@ -63,4 +70,49 @@ class HomeViewModel @Inject constructor( } } } + + private fun updateSort(field: SortField) { + val newDirection = if (field == currentState.sortField) { + toggleDirection(currentState.sortDirection) + } else { + defaultSortDirection(field) + } + + reduce { + copy( + sortField = field, + sortDirection = newDirection, + coins = sortCoins(coins, field, newDirection), + ) + } + } + + private fun sortCoins( + coins: List, + sortField: SortField, + sortDirection: SortDirection, + ): List { + val comparator = when (sortField) { + SortField.Symbol -> compareBy { it.symbol } + SortField.Price -> compareBy { it.price } + SortField.Change -> compareBy { it.priceChangePercentage24h } + } + + return if (sortDirection == SortDirection.Desc) { + coins.sortedWith(comparator).asReversed() + }else{ + coins.sortedWith(comparator) + } + } + + private fun toggleDirection(current: SortDirection): SortDirection { + return if (current == SortDirection.Asc) SortDirection.Desc else SortDirection.Asc + } + + private fun defaultSortDirection(field: SortField): SortDirection { + return when (field) { + SortField.Symbol -> SortDirection.Asc + SortField.Price, SortField.Change -> SortDirection.Desc + } + } } diff --git a/home/presentation/src/main/java/io/soma/cryptobook/home/presentation/component/sortheader/SortHeaderItem.kt b/home/presentation/src/main/java/io/soma/cryptobook/home/presentation/component/sortheader/SortHeaderItem.kt index 9407f43..aeb0682 100644 --- a/home/presentation/src/main/java/io/soma/cryptobook/home/presentation/component/sortheader/SortHeaderItem.kt +++ b/home/presentation/src/main/java/io/soma/cryptobook/home/presentation/component/sortheader/SortHeaderItem.kt @@ -80,7 +80,7 @@ fun SortHeaderItem( text = label, fontFamily = fontFamily, fontWeight = FontWeight.Bold, - fontSize = 14.sp, + fontSize = 12.sp, lineHeight = 20.sp, color = textColor, )