From 9678cdfafbdf85200c83b37dfac6b92a67a8699b Mon Sep 17 00:00:00 2001 From: tigerstone1263 <00fanxi@gmail.com> Date: Tue, 27 Jan 2026 10:40:24 -0800 Subject: [PATCH] feat(home): implement sorting functionality for coin list --- .../home/presentation/HomeContract.kt | 10 ++++ .../home/presentation/HomeScreen.kt | 21 +++++--- .../home/presentation/HomeViewModel.kt | 54 ++++++++++++++++++- .../component/sortheader/SortHeaderItem.kt | 2 +- 4 files changed, 78 insertions(+), 9 deletions(-) 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 0c3d544..ef9d5a9 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( @@ -18,10 +21,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 5c982b9..1ca2fc4 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 7013141..a1e03c5 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 @@ -6,6 +6,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 @@ -29,6 +30,7 @@ class HomeViewModel @Inject constructor( is HomeEvent.OnCoinClicked -> navigationHelper.navigate( AppPage.CoinDetail(event.symbol), ) + is HomeEvent.OnSortClicked -> updateSort(event.field) } } @@ -37,11 +39,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 { it.toCoinItem() }, + coins = sortedCoins, ) } } @@ -59,4 +66,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, )