Skip to content

Commit

Permalink
Add filter by sectors. Update filter by blockchains and some UI changes.
Browse files Browse the repository at this point in the history
  • Loading branch information
ant013 committed Jan 22, 2025
1 parent 59ab15d commit d52b836
Show file tree
Hide file tree
Showing 15 changed files with 305 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1912,6 +1912,8 @@
6BE8A07F2ADE2F950012DE7F /* CurrencyValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BE8A07D2ADE2F950012DE7F /* CurrencyValue.swift */; };
6BE8A0812ADE2FAB0012DE7F /* CurrencyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BE8A0802ADE2FAB0012DE7F /* CurrencyManager.swift */; };
6BE8A0822ADE2FAB0012DE7F /* CurrencyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BE8A0802ADE2FAB0012DE7F /* CurrencyManager.swift */; };
6BFA4E032D26B58A0044567A /* MarketAdvancedSearchCategoriesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BFA4E022D26B58A0044567A /* MarketAdvancedSearchCategoriesView.swift */; };
6BFA4E042D26B58A0044567A /* MarketAdvancedSearchCategoriesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BFA4E022D26B58A0044567A /* MarketAdvancedSearchCategoriesView.swift */; };
ABC9A001F335B695CD066218 /* NftAssetModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9AD35D41AEEBD38AA08B5 /* NftAssetModule.swift */; };
ABC9A005F31836B4EBAB1C97 /* DonateDescriptionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9AD0848221B0EC25C37F3 /* DonateDescriptionCell.swift */; };
ABC9A0073333D3DEC2797D15 /* BackupCloudPassphraseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABC9A8E4CDD143171A1F9C46 /* BackupCloudPassphraseViewController.swift */; };
Expand Down Expand Up @@ -4219,6 +4221,7 @@
6BE8A07A2ADE2F8D0012DE7F /* Currency.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Currency.swift; sourceTree = "<group>"; };
6BE8A07D2ADE2F950012DE7F /* CurrencyValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CurrencyValue.swift; sourceTree = "<group>"; };
6BE8A0802ADE2FAB0012DE7F /* CurrencyManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CurrencyManager.swift; sourceTree = "<group>"; };
6BFA4E022D26B58A0044567A /* MarketAdvancedSearchCategoriesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketAdvancedSearchCategoriesView.swift; sourceTree = "<group>"; };
ABC9A021D71EDD24DFB6BA62 /* CoinProChartModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoinProChartModule.swift; sourceTree = "<group>"; };
ABC9A02C808FCE6082E3F97A /* DebounceTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebounceTextField.swift; sourceTree = "<group>"; };
ABC9A03401172C4C65D66764 /* SingleLineFormTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingleLineFormTextView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -8896,6 +8899,7 @@
D389BC4B2C0DDCF500724504 /* MarketAdvancedSearchBlockchainsView.swift */,
D389BC4E2C0DEF1800724504 /* MarketAdvancedSearchResultsView.swift */,
D389BC512C0DEF2200724504 /* MarketAdvancedSearchResultsViewModel.swift */,
6BFA4E022D26B58A0044567A /* MarketAdvancedSearchCategoriesView.swift */,
);
path = AdvancedSearch;
sourceTree = "<group>";
Expand Down Expand Up @@ -9688,6 +9692,7 @@
11B356476D5E88F21C297B52 /* ManageAccountViewController.swift in Sources */,
11B350860CB79E9C5F032166 /* ManageAccountViewModel.swift in Sources */,
11B3563E71C4AC16DFE8AB76 /* ActiveAccount.swift in Sources */,
6BFA4E042D26B58A0044567A /* MarketAdvancedSearchCategoriesView.swift in Sources */,
6BCD530D2A161F4100993F20 /* ICloudBackupNameViewModel.swift in Sources */,
D3833AF92BF2181800ACECFB /* MarketPair.swift in Sources */,
11B35056B69A06C8CFF3CBB6 /* BackupModule.swift in Sources */,
Expand Down Expand Up @@ -11178,6 +11183,7 @@
11B359F4651EA254E5B0AD00 /* ManageAccountViewController.swift in Sources */,
11B354D8DCBDAA82A6C51205 /* ManageAccountViewModel.swift in Sources */,
11B356C6E9FC6594917B3FF6 /* ActiveAccount.swift in Sources */,
6BFA4E032D26B58A0044567A /* MarketAdvancedSearchCategoriesView.swift in Sources */,
D3833AF82BF2181800ACECFB /* MarketPair.swift in Sources */,
6BE8A0812ADE2FAB0012DE7F /* CurrencyManager.swift in Sources */,
D349031A2BE8DF5F005F147B /* BinancePreSendHandler.swift in Sources */,
Expand Down Expand Up @@ -13239,7 +13245,7 @@
repositoryURL = "https://github.com/horizontalsystems/MarketKit.Swift";
requirement = {
kind = exactVersion;
version = 3.0.13;
version = 3.0.14;
};
};
D3604E7D28F03C1D0066C366 /* XCRemoteSwiftPackageReference "Chart" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,12 @@ extension MarketModule.Top {
switch self {
case .top100: return .top100
case .top200: return .top200
case .top250: return .top250
case .top300: return .top300
case .top500: return .top500
case .top1000: return .top1000
case .top1500: return .top1500
case .top2000: return .top2000
case .top2500: return .top2500
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion UnstoppableWallet/UnstoppableWallet/Models/Stats.swift
Original file line number Diff line number Diff line change
Expand Up @@ -460,11 +460,12 @@ enum StatField: String {
enum StatMarketTop: String {
case top100
case top200
case top250
case top300
case top500
case top1000
case top1500
case top2000
case top2500
}

enum StatEntity: String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ import HsExtensions
import MarketKit

class CoinAnalyticsViewModel: ObservableObject {
private var cancellables = Set<AnyCancellable>()

let coin: Coin
private let marketKit = App.shared.marketKit
private let currencyManager = App.shared.currencyManager
private let purchaseManager = App.shared.purchaseManager
private var tasks = Set<AnyTask>()

@Published private(set) var premiumEnabled: Bool = false
@Published private(set) var state: State = .loading

private let isPurchased = true
private let isPurchased = false

private let ratioFormatter: NumberFormatter = {
let formatter = NumberFormatter()
Expand All @@ -34,6 +38,13 @@ class CoinAnalyticsViewModel: ObservableObject {

init(coin: Coin) {
self.coin = coin
premiumEnabled = purchaseManager.subscription != nil
purchaseManager.$subscription
.receive(on: DispatchQueue.main)
.sink { [weak self] subscription in
self?.premiumEnabled = subscription != nil
}
.store(in: &cancellables)
}

private func handle(analytics: Analytics) async {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,54 +7,60 @@ struct MarketAdvancedSearchBlockchainsView: View {
@Binding var isPresented: Bool

var body: some View {
ThemeNavigationView {
ScrollableThemeView {
VStack(spacing: .margin24) {
ListSection {
ClickableRow {
viewModel.blockchains = Set()
} content: {
Text("selector.any".localized).themeBody(color: .themeGray)

if viewModel.blockchains.isEmpty {
Image("check_1_20").themeIcon(color: .themeJacob)
}
}

ForEach(viewModel.allBlockchains) { blockchain in
VStack(spacing: 0) {
HStack(spacing: .margin16) {
Image("circle_portfolio_24").themeIcon(color: .themeJacob)
Text("market.advanced_search.blockchains".localized).themeHeadline2()
Button(action: { isPresented = false }) { Image("close_3_24").themeIcon() }
}
.padding(.horizontal, .margin32)
.padding(.vertical, .margin24)

BottomGradientWrapper(backgroundColor: .themeLawrence) {
ScrollView {
VStack(spacing: .margin24) {
ListSection {
ClickableRow {
if viewModel.blockchains.contains(blockchain) {
viewModel.blockchains.remove(blockchain)
} else {
viewModel.blockchains.insert(blockchain)
}
viewModel.blockchains = Set()
} content: {
KFImage.url(URL(string: blockchain.type.imageUrl))
.resizable()
.placeholder { RoundedRectangle(cornerRadius: .cornerRadius8).fill(Color.themeSteel20) }
.clipShape(RoundedRectangle(cornerRadius: .cornerRadius8))
.frame(width: .iconSize32, height: .iconSize32)
Text("selector.any".localized).themeBody(color: .themeGray)

Text(blockchain.name).themeBody()

if viewModel.blockchains.contains(blockchain) {
if viewModel.blockchains.isEmpty {
Image("check_1_20").themeIcon(color: .themeJacob)
}
}

ForEach(viewModel.allBlockchains) { blockchain in
ClickableRow {
if viewModel.blockchains.contains(blockchain) {
viewModel.blockchains.remove(blockchain)
} else {
viewModel.blockchains.insert(blockchain)
}
} content: {
Text(blockchain.name).themeBody()

if viewModel.blockchains.contains(blockchain) {
Image("check_1_20").themeIcon(color: .themeJacob)
}
}
}
}
}
.themeListStyle(.bordered)
.padding(EdgeInsets(top: .margin12, leading: .margin16, bottom: .margin32, trailing: .margin16))
}
.padding(EdgeInsets(top: .margin12, leading: .margin16, bottom: .margin32, trailing: .margin16))
}
.navigationTitle("market.advanced_search.blockchains".localized)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Button("button.done".localized) {
isPresented = false
}
} bottomContent: {
Button(buttonTitle()) {
isPresented = false
}
}
}
.buttonStyle(PrimaryButtonStyle(style: .yellow))
}
}
.background(Color.themeLawrence)
}

func buttonTitle() -> String {
viewModel.blockchains.count > 0 ? ["button.select".localized, viewModel.blockchains.count.description].joined(separator: " ") : "button.done".localized
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import MarketKit
import SwiftUI

struct MarketAdvancedSearchCategoriesView: View {
@ObservedObject var viewModel: MarketAdvancedSearchViewModel
@Binding var isPresented: Bool

var body: some View {
VStack(spacing: 0) {
HStack(spacing: .margin16) {
Image("circle_portfolio_24").themeIcon(color: .themeJacob)
Text("market.advanced_search.categories".localized).themeHeadline2()
Button(action: { isPresented = false }) { Image("close_3_24").themeIcon() }
}
.padding(.horizontal, .margin32)
.padding(.vertical, .margin24)

BottomGradientWrapper(backgroundColor: .themeLawrence) {
ScrollView {
VStack(spacing: .margin24) {
ListSection {
switch viewModel.allCategoriesState {
case .loading: EmptyView()
case .failed: EmptyView()
case let .loaded(categories):
ClickableRow {
viewModel.categories = .any
} content: {
Text("selector.any".localized).themeBody(color: .themeGray)

if viewModel.categories == .any {
Image("check_1_20").themeIcon(color: .themeJacob)
}
}

ForEach(categories) { category in
ClickableRow {
switch viewModel.categories {
case .any: viewModel.categories = .list([category.id])
case var .list(array):
if let index = array.firstIndex(of: category.id) {
array.remove(at: index)
} else {
array.append(category.id)
}
viewModel.categories = array.isEmpty ? .any : .list(array)
}
} content: {
Text(category.name).themeBody()

if viewModel.categories.include(id: category.id) {
Image("check_1_20").themeIcon(color: .themeJacob)
}
}
}
}
}
}
.themeListStyle(.bordered)
.padding(EdgeInsets(top: 0, leading: .margin16, bottom: .margin24, trailing: .margin16))
}
} bottomContent: {
Button(buttonTitle()) {
isPresented = false
}
.buttonStyle(PrimaryButtonStyle(style: .yellow))
}
}
.background(Color.themeLawrence)
}

func buttonTitle() -> String {
switch viewModel.categories {
case .any: return "button.done".localized
case let .list(categories): return ["button.select".localized, categories.count.description].joined(separator: " ")
}
}
}

extension CoinCategory: Identifiable {}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ struct MarketAdvancedSearchView: View {

@State var topPresented = false
@State var volumePresented = false
@State var categoriesPresented = false
@State var blockchainsPresented = false
@State var signalsPresented = false
@State var priceCloseToPresented = false
Expand All @@ -29,6 +30,13 @@ struct MarketAdvancedSearchView: View {

VStack(spacing: 0) {
PremiumListSectionHeader()
ListSection {
categoriesRow()
}
.modifier(ColoredBorder())
}

VStack(spacing: 0) {
ListSection {
priceChangeRow()
pricePeriodRow()
Expand Down Expand Up @@ -141,7 +149,10 @@ struct MarketAdvancedSearchView: View {
viewModel.top = top
topPresented = false
} content: {
Text(top.title).themeBody()
VStack(spacing: 1) {
Text(top.title).themeBody()
Text(top.description).themeSubhead2()
}

if viewModel.top == top {
Image("check_1_20").themeIcon(color: .themeJacob)
Expand Down Expand Up @@ -194,6 +205,20 @@ struct MarketAdvancedSearchView: View {
}
}

@ViewBuilder private func categoriesRow() -> some View {
ClickableRow(spacing: .margin8) {
categoriesPresented = true
} content: {
Text("market.advanced_search.categories".localized).textBody()
Spacer()
Text(viewModel.categories.title).textSubhead1(color: color(categoriesFilter: viewModel.categories))
Image("arrow_small_down_20").themeIcon()
}
.sheet(isPresented: $categoriesPresented) {
MarketAdvancedSearchCategoriesView(viewModel: viewModel, isPresented: $categoriesPresented)
}
}

@ViewBuilder private func premiumRow(_ view: some View) -> some View {
if viewModel.premiumEnabled {
ListRow {
Expand Down Expand Up @@ -491,6 +516,13 @@ struct MarketAdvancedSearchView: View {
}
}

private func color(categoriesFilter: MarketAdvancedSearchViewModel.CategoryFilter) -> Color {
switch categoriesFilter {
case .any: return .themeGray
default: return .themeLeah
}
}

private func color(closeToFilter: MarketAdvancedSearchViewModel.PriceCloseToFilter) -> Color {
switch closeToFilter {
case .none: return .themeGray
Expand Down
Loading

0 comments on commit d52b836

Please sign in to comment.