Skip to content

Commit

Permalink
Home Screen load laggines (#1053)
Browse files Browse the repository at this point in the history
  • Loading branch information
GhenadieVP committed Mar 19, 2024
1 parent 1e8eff3 commit 789d213
Show file tree
Hide file tree
Showing 17 changed files with 134 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public struct AccountPortfoliosClient: Sendable {
/// Will return the portfolio after fetch, as well will notify any subscribes through `portfolioForAccount`
public var fetchAccountPortfolio: FetchAccountPortfolio

public var portfolioUpdates: PortfolioUpdates

/// Subscribe to portfolio changes for a given account address
public var portfolioForAccount: PortfolioForAccount

Expand All @@ -21,6 +23,8 @@ extension AccountPortfoliosClient {
public typealias FetchAccountPortfolio = @Sendable (_ address: AccountAddress, _ forceResfresh: Bool) async throws -> AccountPortfolio
public typealias FetchAccountPortfolios = @Sendable (_ addresses: [AccountAddress], _ forceResfresh: Bool) async throws -> [AccountPortfolio]
public typealias PortfolioForAccount = @Sendable (_ address: AccountAddress) async -> AnyAsyncSequence<AccountPortfolio>

public typealias PortfolioUpdates = @Sendable () -> AnyAsyncSequence<Loadable<[AccountPortfolio]>>
public typealias Portfolios = @Sendable () -> [AccountPortfolio]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ extension AccountPortfoliosClient: DependencyKey {

let accounts = try await onLedgerEntitiesClient.getAccounts(accountAddresses).map(\.nonEmptyVaults)

let portfolios = accounts.map { AccountPortfolio(account: $0) }
await state.handlePortfoliosUpdate(portfolios)

/// Put together all resources from already fetched and new accounts
let currentAccounts = state.portfoliosSubject.value.wrappedValue.map { $0.values.map(\.account) } ?? []
let allResources: [ResourceAddress] = {
Expand Down Expand Up @@ -116,9 +119,6 @@ extension AccountPortfoliosClient: DependencyKey {
}
}

let portfolios = accounts.map { AccountPortfolio(account: $0) }
await state.handlePortfoliosUpdate(portfolios)

// Load additional details
_ = await accounts.parallelMap(fetchPoolAndStakeUnitsDetails)

Expand All @@ -137,6 +137,11 @@ extension AccountPortfoliosClient: DependencyKey {

return portfolio
},
portfolioUpdates: {
state.portfoliosSubject
.map { $0.map { Array($0.values) } }
.eraseToAnyAsyncSequence()
},
portfolioForAccount: { address in
await state.portfolioForAccount(address)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ extension AccountPortfoliosClient: TestDependencyKey {
public static let testValue = AccountPortfoliosClient(
fetchAccountPortfolios: unimplemented("\(AccountPortfoliosClient.self).fetchAccountPortfolios"),
fetchAccountPortfolio: unimplemented("\(AccountPortfoliosClient.self).fetchAccountPortfolio"),
portfolioUpdates: unimplemented("\(AccountPortfoliosClient.self).fetchAccountPortfolio"),
portfolioForAccount: unimplemented("\(AccountPortfoliosClient.self).portfolioForAccount"),
portfolios: unimplemented("\(AccountPortfoliosClient.self).portfolios")
)

public static let noop = AccountPortfoliosClient(
fetchAccountPortfolios: { _, _ in throw NoopError() },
fetchAccountPortfolio: { _, _ in throw NoopError() },
portfolioUpdates: { AsyncLazySequence([]).eraseToAnyAsyncSequence() },
portfolioForAccount: { _ in fatalError() },
portfolios: { fatalError() }
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ extension AccountPortfoliosClient.State {
}

func portfolioForAccount(_ address: AccountAddress) -> AnyAsyncSequence<AccountPortfoliosClient.AccountPortfolio> {
portfoliosSubject.compactMap { $0[address].unwrap()?.wrappedValue }.eraseToAnyAsyncSequence()
portfoliosSubject.compactMap { $0[address].unwrap()?.wrappedValue }.removeDuplicates().eraseToAnyAsyncSequence()
}

private func setOrUpdateAccountPortfolio(_ portfolio: AccountPortfoliosClient.AccountPortfolio) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ extension TokenPricesClient.TokenPrices {
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = Int(RETDecimal.maxDivisibility)
formatter.roundingMode = .down
formatter.decimalSeparator = "." // Enfore dot notation for RETDecimal

self = tokenPricesResponse.tokens.reduce(into: [:]) { partialResult, next in
let trimmed = formatter.string(for: next.price) ?? ""
Expand Down
29 changes: 23 additions & 6 deletions RadixWallet/Core/FeaturePrelude/Loadable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ extension Loadable {
}
}

public func firstd(where predicate: (Value.Element) -> Bool) -> Loadable<Value.Element?> where Value: Sequence {
public func first(where predicate: (Value.Element) -> Bool) -> Loadable<Value.Element?> where Value: Sequence {
switch self {
case .idle:
return .idle
Expand Down Expand Up @@ -292,6 +292,10 @@ extension Loadable {
concat(other).map(join)
}

public func reduce<Element>(_ join: (Element) -> Void) -> Void where Value == Array<Element> {

}

public mutating func mutateValue(_ mutate: (inout Value) -> Void) {
switch self {
case .idle, .loading, .failure:
Expand All @@ -307,16 +311,29 @@ extension Loadable {
public mutating func refresh(
from other: Loadable<Value>,
valueChangeMap: (_ old: Value, _ new: Value) -> Value = { _, new in new }
) {
) where Value: Equatable {
switch (self, other) {
// If `other` is success, update the content regardless of the current state
case let (.success(oldValue), .success(newValue)):
self = .success(valueChangeMap(oldValue, newValue))
case let (_, .success(otherValue)):
// Update to success if no current value
case let (.idle, .success(otherValue)),
let (.loading, .success(otherValue)),
let (.failure, .success(otherValue)):

self = .success(otherValue)

// Update to new value only if it changed
case let (.success(oldValue), .success(newValue)):
if oldValue != newValue {
self = .success(valueChangeMap(oldValue, newValue))
}

// If current state is success, don't update if `other` is loading or failed
case (.success, _):
break

case (.loading, .loading),
(.idle, .idle):
break

// If current state is other than .success
case let (_, other):
self = other
Expand Down
12 changes: 8 additions & 4 deletions RadixWallet/Features/AssetsFeature/AssetsView+Reducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ public struct AssetsView: Sendable, FeatureReducer {
return nil
}

return .init(sections: sections)
return .init(sections: sections, destination: state.resources.fungibleTokenList?.destination)
}()

state.accountPortfolio.refresh(from: .success(portfolio))
Expand All @@ -210,7 +210,8 @@ public struct AssetsView: Sendable, FeatureReducer {
},
isSelected: mode.nonXrdRowSelected(poolUnit.resource.resourceAddress)
)
}.asIdentifiable()
}.asIdentifiable(),
destination: state.resources.poolUnitsList?.destination
)

let stakes = portfolio.account.poolUnitResources.radixNetworkStakes
Expand All @@ -234,13 +235,14 @@ public struct AssetsView: Sendable, FeatureReducer {
dict[resource] = selectedtokens
}
} : nil,
stakeUnitDetails: state.accountPortfolio.stakeUnitDetails.flatten()
stakeUnitDetails: state.accountPortfolio.stakeUnitDetails.flatten(),
destination: state.resources.stakeUnitList?.destination
)

state.totalFiatWorth.refresh(from: portfolio.totalFiatWorth)
state.resources = .init(
fungibleTokenList: fungibleTokenList,
nonFungibleTokenList: !nfts.isEmpty ? .init(rows: .init(uniqueElements: nfts)) : nil,
nonFungibleTokenList: !nfts.isEmpty ? .init(rows: nfts.asIdentifiable(), destination: state.resources.nonFungibleTokenList?.destination) : nil,
stakeUnitList: stakeUnitList,
poolUnitsList: poolUnitList
)
Expand All @@ -250,6 +252,8 @@ public struct AssetsView: Sendable, FeatureReducer {
extension AccountPortfoliosClient.AccountPortfolio {
mutating func refresh(from portfolio: AccountPortfoliosClient.AccountPortfolio) {
self.account = portfolio.account
self.isCurrencyAmountVisible = portfolio.isCurrencyAmountVisible
self.fiatCurrency = portfolio.fiatCurrency
self.stakeUnitDetails.refresh(from: portfolio.stakeUnitDetails)
self.poolUnitDetails.refresh(from: portfolio.poolUnitDetails)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,10 @@ import SwiftUI
// MARK: - FungibleAssetList
public struct FungibleAssetList: Sendable, FeatureReducer {
public struct State: Sendable, Hashable {
public var sections: IdentifiedArrayOf<FungibleAssetList.Section.State>
public var sections: IdentifiedArrayOf<FungibleAssetList.Section.State> = []

@PresentationState
public var destination: Destination.State?

public init(
sections: IdentifiedArrayOf<FungibleAssetList.Section.State> = []
) {
self.sections = sections
}
}

@CasePathable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ extension ResourceBalanceView {
}
.disabled(onTap == nil)
.buttonStyle(.borderless)
.roundedCorners(strokeColor: .red) // .app.gray3
.roundedCorners(strokeColor: .app.gray3)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ public struct NonFungibleAssetList: Sendable, FeatureReducer {

@PresentationState
public var destination: Destination.State?

public init(rows: IdentifiedArrayOf<NonFungibleAssetList.Row.State>) {
self.rows = rows
}
}

public enum ChildAction: Sendable, Equatable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ struct ValidatorStakeView: View {
onTap: onTap,
onClaimAllTapped: onClaimAllTapped
)
.padding(.small1)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ public struct StakeUnitList: Sendable, FeatureReducer {
account: OnLedgerEntity.Account,
selectedLiquidStakeUnits: IdentifiedArrayOf<OnLedgerEntity.OwnedFungibleResource>?,
selectedStakeClaimTokens: SelectedStakeClaimTokens?,
stakeUnitDetails: Loadable<IdentifiedArrayOf<OnLedgerEntitiesClient.OwnedStakeDetails>>
stakeUnitDetails: Loadable<IdentifiedArrayOf<OnLedgerEntitiesClient.OwnedStakeDetails>>,
destination: Destination.State? = nil
) {
self.account = account
self.selectedLiquidStakeUnits = selectedLiquidStakeUnits
self.selectedStakeClaimTokens = selectedStakeClaimTokens
self.destination = destination

switch stakeUnitDetails {
case .idle, .loading:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ extension Home {
public var id: AccountAddress { account.address }
public var accountWithInfo: AccountWithInfo

public var portfolio: Loadable<AccountPortfoliosClient.AccountPortfolio>
public var accountWithResources: Loadable<OnLedgerEntity.Account>
public var showFiatWorth: Bool = true
public var totalFiatWorth: Loadable<FiatWorth>

public init(
account: Profile.Network.Account
) {
self.accountWithInfo = .init(account: account)
self.portfolio = .loading
self.accountWithResources = .loading
self.totalFiatWorth = .loading
}
}
Expand All @@ -29,7 +29,8 @@ extension Home {
}

public enum InternalAction: Sendable, Equatable {
case accountPortfolioUpdate(AccountPortfoliosClient.AccountPortfolio)
case accountUpdated(OnLedgerEntity.Account)
case fiatWorthUpdated(Loadable<FiatWorth>)
case checkAccountAccessToMnemonic
}

Expand All @@ -46,21 +47,10 @@ extension Home {
public func reduce(into state: inout State, viewAction: ViewAction) -> Effect<Action> {
switch viewAction {
case .task:
let accountAddress = state.account.address
if state.portfolio.wrappedValue == nil {
state.portfolio = .loading
}

self.checkAccountAccessToMnemonic(state: &state)

return .run { send in
for try await accountPortfolio in await accountPortfoliosClient.portfolioForAccount(accountAddress) {
guard !Task.isCancelled else {
return
}
await send(.internal(.accountPortfolioUpdate(accountPortfolio)))
}
}
return .none

case .exportMnemonicButtonTapped:
return .send(.delegate(.exportMnemonic))

Expand All @@ -74,23 +64,26 @@ extension Home {

public func reduce(into state: inout State, internalAction: InternalAction) -> Effect<Action> {
switch internalAction {
case let .accountPortfolioUpdate(portfolio):
state.isDappDefinitionAccount = portfolio.account.metadata.accountType == .dappDefinition
case let .accountUpdated(account):
assert(account.address == state.account.address)

assert(portfolio.account.address == state.account.address)
state.isDappDefinitionAccount = account.metadata.accountType == .dappDefinition
state.accountWithResources.refresh(from: .success(account))

state.portfolio = .success(portfolio)
state.totalFiatWorth.refresh(from: portfolio.totalFiatWorth)
return .send(.internal(.checkAccountAccessToMnemonic))

case .checkAccountAccessToMnemonic:
checkAccountAccessToMnemonic(state: &state)
return .none

case let .fiatWorthUpdated(fiatWorth):
state.totalFiatWorth.refresh(from: fiatWorth)
return .none
}
}

private func checkAccountAccessToMnemonic(state: inout State) {
state.checkAccountAccessToMnemonic(portfolio: state.portfolio.account.wrappedValue)
state.checkAccountAccessToMnemonic(portfolio: state.accountWithResources.wrappedValue)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,15 @@ extension Home.AccountRow {
self.appearanceID = state.account.appearanceID
self.showFiatWorth = state.showFiatWorth
self.fiatWorth = state.totalFiatWorth
self.isLoadingResources = state.portfolio.isLoading
self.isLoadingResources = state.accountWithResources.isLoading

self.tag = .init(state: state)
self.isLedgerAccount = state.isLedgerAccount

self.mnemonicHandlingCallToAction = state.mnemonicHandlingCallToAction

// Resources
guard let portfolio = state.portfolio.wrappedValue else {
guard let accountWithResources = state.accountWithResources.wrappedValue else {
self.fungibleResourceIcons = []
self.nonFungibleResourcesCount = 0
self.stakedValidatorsCount = 0
Expand All @@ -64,13 +64,13 @@ extension Home.AccountRow {
return
}

let fungibleResources = portfolio.account.fungibleResources
let fungibleResources = accountWithResources.fungibleResources
let xrdIcon: [Thumbnail.TokenContent] = fungibleResources.xrdResource != nil ? [.xrd] : []
let otherIcons: [Thumbnail.TokenContent] = fungibleResources.nonXrdResources.map { .other($0.metadata.iconURL) }
self.fungibleResourceIcons = xrdIcon + otherIcons
self.nonFungibleResourcesCount = portfolio.account.nonFungibleResources.count
self.stakedValidatorsCount = portfolio.account.poolUnitResources.radixNetworkStakes.count
self.poolUnitsCount = portfolio.account.poolUnitResources.poolUnits.count
self.nonFungibleResourcesCount = accountWithResources.nonFungibleResources.count
self.stakedValidatorsCount = accountWithResources.poolUnitResources.radixNetworkStakes.count
self.poolUnitsCount = accountWithResources.poolUnitResources.poolUnits.count
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ extension Home.State {
.init(
hasNotification: shouldWriteDownPersonasSeedPhrase,
showRadixBanner: showRadixBanner,
totalFiatWorth: totalFiatWorth
totalFiatWorth: showFiatWorth ? totalFiatWorth : nil
)
}
}
Expand Down
Loading

0 comments on commit 789d213

Please sign in to comment.