Sorting List data with MVVM and animations | SwiftUI Crypto App #17
enum SortOption {
case rank, rankReversed, holdings, holdingsReversed, price, priceReversed
}
@Published var sortOption: SortOption = .holdings
$searchText
.combineLatest(coinDataService.$allCoins, $sortOption)
.debounce(for: .seconds(0.5), scheduler: DispatchQueue.main)
.map(filterAndSortCoins)
.sink { [weak self] coinModels in
self?.allCoins = coinModels
}
.store(in: &cancellables)
combineLatest
를 통해 정렬 옵션 퍼블리셔를 함께 관리filterAndSortCoins
를 통해 정렬된 코인 데이터 리턴private func filterAndSortCoins(text: String, coins: [CoinModel], sort: SortOption) -> [CoinModel] {
var updatedCoins = filterCoins(text: text, coins: coins)
sortCoins(sort: sort, coins: &updatedCoins)
return updatedCoins
}
private func sortCoins(sort: SortOption, coins: inout [CoinModel]) {
switch sortOption {
case .rank, .holdings:
coins.sort(by: {$0.rank < $1.rank})
case .rankReversed, .holdingsReversed:
coins.sort(by: {$0.rank > $1.rank})
case .price:
coins.sort(by: {$0.currentPrice > $1.currentPrice})
case .priceReversed:
coins.sort(by: {$0.currentPrice < $1.currentPrice})
}
}
private func sortPortfoiloCoinsIfNeeded(coins: [CoinModel]) -> [CoinModel] {
switch sortOption {
case .holdings:
return coins.sorted(by: {$0.currentHoldingsValue > $1.currentHoldingsValue })
case .holdingsReversed:
return coins.sorted(by: {$0.currentHoldingsValue < $1.currentHoldingsValue })
default: return coins
}
}
allCoins
와 연관되어 있기 때문에 별도로 관리 $allCoins
.combineLatest(portfolioDataService.$savedEntities)
.map(mapAllCoinsToPortfolioCoins)
.sink { [weak self] coinModels in
guard let self = self else { return }
self.portfolioCoins = self.sortPortfoiloCoinsIfNeeded(coins: coinModels)
}
.store(in: &cancellables)
allCoins
이 변경되기 때문에 해당 구독 코드 호출sortPortfolioIfNeeded
함수 단에서 현재 뷰 모델 내 전역으로 관리하고 있는 sortOption
을 통해 정렬된 포트폴리오 코인 데이터 모델 리턴HStack(spacing: 4) {
Text("Coin")
Image(systemName: "chevron.down")
.opacity((viewModel.sortOption == .rank || viewModel.sortOption == .rankReversed) ? 1.0 : 0.0)
.rotationEffect(Angle(degrees: viewModel.sortOption == .rank ? 0 : 180))
}
.onTapGesture {
withAnimation(.default) {
viewModel.sortOption = viewModel.sortOption == .rank ? .rankReversed : .rank
}
}