Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rank badges to MarketEtf module #5911

Merged
merged 1 commit into from
Jun 12, 2024
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
32 changes: 19 additions & 13 deletions UnstoppableWallet/UnstoppableWallet/Extensions/Etf.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,6 @@ import Foundation
import MarketKit
import UIKit

extension Etf: Hashable {
public static func == (lhs: Etf, rhs: Etf) -> Bool {
lhs.ticker == rhs.ticker
}

public func hash(into hasher: inout Hasher) {
hasher.combine(ticker)
}
}

extension Etf {
var imageUrl: String {
let scale = Int(UIScreen.main.scale)
Expand All @@ -26,9 +16,25 @@ extension Etf {
}
}

extension [Etf] {
func sorted(sortBy: MarketEtfViewModel.SortBy, timePeriod: MarketEtfViewModel.TimePeriod) -> [Etf] {
sorted { lhsEtf, rhsEtf in
struct RankedEtf: Hashable {
let etf: Etf
let rank: Int

public static func == (lhs: RankedEtf, rhs: RankedEtf) -> Bool {
lhs.etf.ticker == rhs.etf.ticker
}

public func hash(into hasher: inout Hasher) {
hasher.combine(etf.ticker)
}
}

extension [RankedEtf] {
func sorted(sortBy: MarketEtfViewModel.SortBy, timePeriod: MarketEtfViewModel.TimePeriod) -> [RankedEtf] {
sorted { lhsRankedEtf, rhsRankedEtf in
let lhsEtf = lhsRankedEtf.etf
let rhsEtf = rhsRankedEtf.etf

switch sortBy {
case .highestAssets, .lowestAssets:
guard let lhsAssets = lhsEtf.totalAssets else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct MarketEtfView: View {
ProgressView()
Spacer()
}
case let .loaded(etfs):
case let .loaded(rankedEtfs):
ScrollViewReader { proxy in
ThemeList(bottomSpacing: .margin16, invisibleTopView: true) {
header()
Expand All @@ -40,7 +40,7 @@ struct MarketEtfView: View {
.listRowInsets(EdgeInsets())
.listRowSeparator(.hidden)

list(etfs: etfs)
list(rankedEtfs: rankedEtfs)
}
.onChange(of: viewModel.sortBy) { _ in withAnimation { proxy.scrollTo(themeListTopViewId) } }
.onChange(of: viewModel.timePeriod) { _ in withAnimation { proxy.scrollTo(themeListTopViewId) } }
Expand Down Expand Up @@ -137,14 +137,17 @@ struct MarketEtfView: View {
)
}

@ViewBuilder private func list(etfs: [Etf]) -> some View {
@ViewBuilder private func list(rankedEtfs: [RankedEtf]) -> some View {
Section {
ListForEach(etfs) { etf in
ListForEach(rankedEtfs) { rankedEtf in
let etf = rankedEtf.etf

ListRow {
itemContent(
imageUrl: URL(string: etf.imageUrl),
ticker: etf.ticker,
name: etf.name,
rank: rankedEtf.rank,
totalAssets: etf.totalAssets,
change: etf.inflow(timePeriod: viewModel.timePeriod)
)
Expand All @@ -165,6 +168,7 @@ struct MarketEtfView: View {
imageUrl: nil,
ticker: "ABCD",
name: "Ticker Name",
rank: 12,
totalAssets: 123_345_678,
change: index % 2 == 0 ? 123_456 : -123_456
)
Expand All @@ -178,7 +182,7 @@ struct MarketEtfView: View {
}
}

@ViewBuilder private func itemContent(imageUrl: URL?, ticker: String, name: String, totalAssets: Decimal?, change: Decimal?) -> some View {
@ViewBuilder private func itemContent(imageUrl: URL?, ticker: String, name: String, rank: Int, totalAssets: Decimal?, change: Decimal?) -> some View {
KFImage.url(imageUrl)
.resizable()
.placeholder { RoundedRectangle(cornerRadius: .cornerRadius8).fill(Color.themeSteel20) }
Expand All @@ -193,7 +197,10 @@ struct MarketEtfView: View {
}

HStack(spacing: .margin8) {
Text(name).textSubhead2()
HStack(spacing: .margin4) {
BadgeViewNew(text: "\(rank)")
Text(name).textSubhead2()
}
Spacer()
DiffText(change, currency: viewModel.currency)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ class MarketEtfViewModel: ObservableObject {
switch internalState {
case .loading:
state = .loading
case let .loaded(etfs):
state = .loaded(etfs: etfs.sorted(sortBy: sortBy, timePeriod: timePeriod))
case let .loaded(rankedEtfs):
state = .loaded(rankedEtfs: rankedEtfs.sorted(sortBy: sortBy, timePeriod: timePeriod))
case let .failed(error):
state = .failed(error: error)
}
Expand All @@ -73,9 +73,11 @@ extension MarketEtfViewModel {
Task { [weak self, marketKit, currency] in
do {
let etfs = try await marketKit.etfs(currencyCode: currency.code)
let sortedEtfs = etfs.sorted { $0.totalAssets ?? 0 > $1.totalAssets ?? 0 }
let rankedEtfs = sortedEtfs.enumerated().map { RankedEtf(etf: $1, rank: $0 + 1) }

await MainActor.run { [weak self] in
self?.internalState = .loaded(etfs: etfs)
self?.internalState = .loaded(rankedEtfs: rankedEtfs)
}
} catch {
await MainActor.run { [weak self] in
Expand All @@ -90,7 +92,7 @@ extension MarketEtfViewModel {
extension MarketEtfViewModel {
enum State {
case loading
case loaded(etfs: [Etf])
case loaded(rankedEtfs: [RankedEtf])
case failed(error: Error)
}

Expand All @@ -111,14 +113,14 @@ extension MarketEtfViewModel {

var title: String {
switch self {
case let .period(timePeriod): return "market.time_period.\(timePeriod.rawValue)".localized
case let .period(timePeriod): return timePeriod.title
case .all: return "market.etf.period.all".localized
}
}

var shortTitle: String {
switch self {
case let .period(timePeriod): return "market.time_period.\(timePeriod.rawValue).short".localized
case let .period(timePeriod): return timePeriod.shortTitle
case .all: return "market.etf.period.all".localized
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,17 @@ extension [MarketKit.TopPlatform] {

extension HsTimePeriod {
var title: String {
"market.time_period.\(rawValue)".localized
switch self {
case .hour24: return "market.time_period.1d".localized
default: return "market.time_period.\(rawValue)".localized
}
}

var shortTitle: String {
"market.time_period.\(rawValue).short".localized
switch self {
case .hour24: return "market.time_period.1d.short".localized
default: return "market.time_period.\(rawValue).short".localized
}
}

init?(_ periodType: HsPeriodType) {
Expand All @@ -208,11 +214,17 @@ extension HsTimePeriod {

extension WatchlistTimePeriod {
var title: String {
"market.time_period.\(rawValue)".localized
switch self {
case .hour24: return "market.time_period.1d".localized
default: return "market.time_period.\(rawValue)".localized
}
}

var shortTitle: String {
"market.time_period.\(rawValue).short".localized
switch self {
case .hour24: return "market.time_period.1d.short".localized
default: return "market.time_period.\(rawValue).short".localized
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,6 @@
"market.top_coins" = "Top %@";

"market.time_period.title" = "Period";
"market.time_period.24h" = "24 Hours";
"market.time_period.1d" = "1 Day";
"market.time_period.1w" = "1 Week";
"market.time_period.2w" = "2 Weeks";
Expand All @@ -734,7 +733,6 @@
"market.time_period.1y" = "1 Year";
"market.time_period.2y" = "2 Years";
"market.time_period.5y" = "5 Years";
"market.time_period.24h.short" = "24H";
"market.time_period.1d.short" = "1D";
"market.time_period.1w.short" = "1W";
"market.time_period.2w.short" = "2W";
Expand Down