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

TRCL-3711 TRCL-3712 Simple UI market list and search #321

Open
wants to merge 3 commits into
base: feature/sui_1
Choose a base branch
from
Open
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
16 changes: 16 additions & 0 deletions dydx/dydxPresenters/dydxPresenters.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
0280B3A629CB63E10017D64A /* dydxOnboardWelcomeViewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0280B3A529CB63E10017D64A /* dydxOnboardWelcomeViewBuilder.swift */; };
0284202F29AD727200C0E7CC /* dydxViews.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0284201F29AD725000C0E7CC /* dydxViews.framework */; };
02860A9F29C15E760079E644 /* dydxOnboardScanViewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02860A9329C15E760079E644 /* dydxOnboardScanViewBuilder.swift */; };
028CF14F2D1489E900476930 /* dydxSimpleUIMarketSearchViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 028CF1412D1489E800476930 /* dydxSimpleUIMarketSearchViewPresenter.swift */; };
028DB3402A05893D0090BE58 /* dydxProfileHeaderViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 028DB33F2A05893D0090BE58 /* dydxProfileHeaderViewPresenter.swift */; };
028FB3EC2AD642B30013136C /* dydxTokenConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 028FB3EB2AD642B30013136C /* dydxTokenConstants.swift */; };
0295392329FB256E009026E3 /* dydxThemeViewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0295392229FB256E009026E3 /* dydxThemeViewBuilder.swift */; };
Expand All @@ -104,6 +105,7 @@
02D6DAFA2D1234B7008AAEA1 /* dydxSimpleUIMarketsViewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02D6DAF92D1234B4008AAEA1 /* dydxSimpleUIMarketsViewBuilder.swift */; };
02D6DAFC2D123576008AAEA1 /* dydxRootBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02D6DAFB2D123570008AAEA1 /* dydxRootBuilder.swift */; };
02D6DB272D124AAF008AAEA1 /* dydxAppModeViewBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02D6DB262D124AAD008AAEA1 /* dydxAppModeViewBuilder.swift */; };
02D6DBB92D134BEA008AAEA1 /* dydxSimpleUIMarketListViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02D6DBB82D134BE8008AAEA1 /* dydxSimpleUIMarketListViewPresenter.swift */; };
02D9518C2C926B9C007BB2B4 /* dydxNotificationPrimerViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02D9518B2C926B9C007BB2B4 /* dydxNotificationPrimerViewPresenter.swift */; };
02DA6E0D2AD897EE0048126C /* starkex-lib.js in Resources */ = {isa = PBXBuildFile; fileRef = 02DA6DFF2AD897EE0048126C /* starkex-lib.js */; };
02DA6E0E2AD897EE0048126C /* starkex-eth.js in Resources */ = {isa = PBXBuildFile; fileRef = 02DA6E0C2AD897EE0048126C /* starkex-eth.js */; };
Expand Down Expand Up @@ -481,6 +483,7 @@
0280B3A529CB63E10017D64A /* dydxOnboardWelcomeViewBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxOnboardWelcomeViewBuilder.swift; sourceTree = "<group>"; };
0284201929AD725000C0E7CC /* dydxViews.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = dydxViews.xcodeproj; path = ../dydxViews/dydxViews.xcodeproj; sourceTree = "<group>"; };
02860A9329C15E760079E644 /* dydxOnboardScanViewBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = dydxOnboardScanViewBuilder.swift; sourceTree = "<group>"; };
028CF1412D1489E800476930 /* dydxSimpleUIMarketSearchViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSimpleUIMarketSearchViewPresenter.swift; sourceTree = "<group>"; };
028DB33F2A05893D0090BE58 /* dydxProfileHeaderViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxProfileHeaderViewPresenter.swift; sourceTree = "<group>"; };
028FB3EB2AD642B30013136C /* dydxTokenConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxTokenConstants.swift; sourceTree = "<group>"; };
0295392229FB256E009026E3 /* dydxThemeViewBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxThemeViewBuilder.swift; sourceTree = "<group>"; };
Expand All @@ -503,6 +506,7 @@
02D6DAF92D1234B4008AAEA1 /* dydxSimpleUIMarketsViewBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSimpleUIMarketsViewBuilder.swift; sourceTree = "<group>"; };
02D6DAFB2D123570008AAEA1 /* dydxRootBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxRootBuilder.swift; sourceTree = "<group>"; };
02D6DB262D124AAD008AAEA1 /* dydxAppModeViewBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxAppModeViewBuilder.swift; sourceTree = "<group>"; };
02D6DBB82D134BE8008AAEA1 /* dydxSimpleUIMarketListViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxSimpleUIMarketListViewPresenter.swift; sourceTree = "<group>"; };
02D9518B2C926B9C007BB2B4 /* dydxNotificationPrimerViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = dydxNotificationPrimerViewPresenter.swift; sourceTree = "<group>"; };
02DA6DFF2AD897EE0048126C /* starkex-lib.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "starkex-lib.js"; sourceTree = "<group>"; };
02DA6E0C2AD897EE0048126C /* starkex-eth.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "starkex-eth.js"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1292,6 +1296,7 @@
02D6DAF82D1234A8008AAEA1 /* Markets */ = {
isa = PBXGroup;
children = (
02D6DBB72D134BE0008AAEA1 /* components */,
02D6DAF92D1234B4008AAEA1 /* dydxSimpleUIMarketsViewBuilder.swift */,
);
path = Markets;
Expand All @@ -1305,6 +1310,15 @@
path = AppMode;
sourceTree = "<group>";
};
02D6DBB72D134BE0008AAEA1 /* components */ = {
isa = PBXGroup;
children = (
028CF1412D1489E800476930 /* dydxSimpleUIMarketSearchViewPresenter.swift */,
02D6DBB82D134BE8008AAEA1 /* dydxSimpleUIMarketListViewPresenter.swift */,
);
path = components;
sourceTree = "<group>";
};
02DC87862CD441B500F865C5 /* History */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -2096,12 +2110,14 @@
270E7E242A5F6B1B00136793 /* dydxTradeInputSideViewPresenter.swift in Sources */,
278A4D1E2B8EA95A003898EB /* dydxCollectFeedbackActionBuilder.swift in Sources */,
2741E3732A689740000FA190 /* dydxDirectionColorPreferenceViewBuilder.swift in Sources */,
02D6DBB92D134BEA008AAEA1 /* dydxSimpleUIMarketListViewPresenter.swift in Sources */,
0236F12D296B91BD00EB995F /* dydxPortfolioOrdersViewPresenter.swift in Sources */,
0280B3A629CB63E10017D64A /* dydxOnboardWelcomeViewBuilder.swift in Sources */,
023848D72A9E785900B1A673 /* dydxTosViewBuilder.swift in Sources */,
0238FC4C296DA55A002E1C1A /* dydxOrderDetailsViewBuilder.swift in Sources */,
02F95A7E2A1D314400828F9A /* dydxPortfolioSelectorViewPresenter.swift in Sources */,
020EB697299D36AD00E8026B /* dydxApiStatusWorker.swift in Sources */,
028CF14F2D1489E900476930 /* dydxSimpleUIMarketSearchViewPresenter.swift in Sources */,
02A5C85E297FBCD700FFE1F9 /* dydxTransferViewBuilder.swift in Sources */,
023848C22A9E637C00B1A673 /* SettingsLandingViewPresenter.swift in Sources */,
0258BA23299294BF0098E1BE /* dydxProfileViewBuilder.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//
// dydxSimpleUIMarketListViewPresenter.swift
// dydxPresenters
//
// Created by Rui Huang on 18/12/2024.
//

import Utilities
import dydxViews
import PlatformParticles
import RoutingKit
import ParticlesKit
import PlatformUI
import dydxStateManager
import Abacus
import Combine
import dydxFormatter

protocol dydxSimpleUIMarketListViewPresenterProtocol: HostedViewPresenterProtocol {
var viewModel: dydxSimpleUIMarketListViewModel? { get }
}

class dydxSimpleUIMarketListViewPresenter: HostedViewPresenter<dydxSimpleUIMarketListViewModel>, dydxSimpleUIMarketListViewPresenterProtocol {

@Published var searchText: String = ""

override init() {
super.init()

viewModel = dydxSimpleUIMarketListViewModel()
}

override func start() {
super.start()

let searchTextPublisher = $searchText.map({ $0.lowercased() }).removeDuplicates()

Publishers
.CombineLatest4(AbacusStateManager.shared.state.marketList,
AbacusStateManager.shared.state.assetMap,
AbacusStateManager.shared.state.selectedSubaccountPositions,
searchTextPublisher
)
.sink { [weak self] markets, assetMap, positions, searchText in
self?.updateMarketList(markets: markets, assetMap: assetMap, positions: positions, searchText: searchText)
}
.store(in: &subscriptions)
}

private func updateMarketList(markets: [PerpetualMarket],
assetMap: [String: Asset],
positions: [SubaccountPosition],
searchText: String?) {
let markets = markets.filter { $0.status?.canTrade == true }
viewModel?.markets = markets
.compactMap { market in
guard let asset = assetMap[market.assetId] else {
return nil
}
if let searchText = searchText, searchText.isNotEmpty,
asset.displayableAssetId.lowercased().contains(searchText) == false,
asset.name?.lowercased().contains(searchText) == false {
return nil
}
let position = positions.first { position in
position.id == market.id
}
return dydxSimpleUIMarketViewModel.createFrom(market: market, asset: asset, position: position)
}
.sorted { lhs, rhs in
if lhs.leverage != nil && rhs.leverage != nil {
return (lhs.volumn ?? 0) > (rhs.volumn ?? 0)
} else if lhs.leverage != nil {
return true
} else if rhs.leverage != nil {
return false
}
return (lhs.volumn ?? 0) > (rhs.volumn ?? 0)
}
}
}

private extension dydxSimpleUIMarketViewModel {
static func createFrom(market: PerpetualMarket, asset: Asset?, position: SubaccountPosition?) -> dydxSimpleUIMarketViewModel {
let price = dydxFormatter.shared.dollar(number: market.oraclePrice?.doubleValue, digits: market.configs?.displayTickSizeDecimals?.intValue ?? 2)
let change = SignedAmountViewModel(amount: market.priceChange24HPercent?.doubleValue,
displayType: .percent,
coloringOption: .allText)
var side = SideTextViewModel(side: .custom(DataLocalizer.localize(path: "APP.GENERAL.NO_POSITION")))
if let position = position {
if position.side.current == Abacus.PositionSide.long_ {
side = SideTextViewModel(side: .long)
} else if position.side.current == Abacus.PositionSide.short_ {
side = SideTextViewModel(side: .short)
}
}
let leverage = dydxFormatter.shared.raw(number: position?.leverage.current?.doubleValue, digits: 3)
return dydxSimpleUIMarketViewModel(marketId: market.id,
assetName: asset?.displayableAssetId ?? market.assetId,
iconUrl: asset?.resources?.imageUrl,
price: price,
change: change,
sideText: side,
leverage: leverage,
volumn: market.perpetual?.volume24HUSDC?.doubleValue,
onMarketSelected: {
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// dydxSimpleUIMarketSearchViewPresenter.swift
// dydxPresenters
//
// Created by Rui Huang on 19/12/2024.
//

import Utilities
import dydxViews
import PlatformParticles
import RoutingKit
import ParticlesKit
import PlatformUI

protocol dydxSimpleUIMarketSearchViewPresenterProtocol: HostedViewPresenterProtocol {
var viewModel: dydxSimpleUIMarketSearchViewModel? { get }
}

class dydxSimpleUIMarketSearchViewPresenter: HostedViewPresenter<dydxSimpleUIMarketSearchViewModel>, dydxSimpleUIMarketSearchViewPresenterProtocol {
override init() {
super.init()

viewModel = dydxSimpleUIMarketSearchViewModel()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,30 @@ public protocol dydxSimpleUIMarketsViewPresenterProtocol: HostedViewPresenterPro

public class dydxSimpleUIMarketsViewPresenter: HostedViewPresenter<dydxSimpleUIMarketsViewModel>, dydxSimpleUIMarketsViewPresenterProtocol {

private let marketListPresenter = dydxSimpleUIMarketListViewPresenter()
private let marketSearchPresenter = dydxSimpleUIMarketSearchViewPresenter()

private lazy var childPresenters: [HostedViewPresenterProtocol] = [
marketListPresenter,
marketSearchPresenter
]

override init() {
super.init()
let viewModel = dydxSimpleUIMarketsViewModel()

marketListPresenter.$viewModel.assign(to: &viewModel.$marketList)
marketSearchPresenter.$viewModel.assign(to: &viewModel.$marketSearch)
marketSearchPresenter.viewModel?.$searchText.assign(to: &marketListPresenter.$searchText)
marketSearchPresenter.viewModel?.$focused.assign(to: &viewModel.$keyboardUp)

viewModel = dydxSimpleUIMarketsViewModel()
viewModel?.onSettingTapped = {
viewModel.onSettingTapped = {
Router.shared?.navigate(to: RoutingRequest(path: "/settings/app_mode"), animated: true, completion: nil)
}

super.init()

self.viewModel = viewModel

attachChildren(workers: childPresenters)
}
}
Loading