diff --git a/Sources/BraveWallet/Crypto/NFT/NFTView.swift b/Sources/BraveWallet/Crypto/NFT/NFTView.swift index 9c99c649949..e3b6027dbb1 100644 --- a/Sources/BraveWallet/Crypto/NFT/NFTView.swift +++ b/Sources/BraveWallet/Crypto/NFT/NFTView.swift @@ -113,28 +113,40 @@ struct NFTView: View { private var nftHeaderView: some View { HStack { - Text(Strings.Wallet.assetsTitle) - .font(.title3.weight(.semibold)) - .foregroundColor(Color(braveSystemName: .textPrimary)) + Menu { + Picker("", selection: $nftStore.displayType) { + ForEach(NFTStore.NFTDisplayType.allCases) { type in + Text(type.dropdownTitle) + .foregroundColor(Color(.secondaryBraveLabel)) + .tag(type) + } + } + .pickerStyle(.inline) + } label: { + HStack(spacing: 12) { + Text(nftStore.displayType.dropdownTitle) + .font(.subheadline.weight(.semibold)) + Text("\(nftStore.totalDisplayNFTCounter)") + .padding(.horizontal, 8) + .padding(.vertical, 4) + .font(.caption2.weight(.semibold)) + .background( + Color(uiColor: WalletV2Design.displayNFTCounterColor) + .cornerRadius(4) + ) + Image(braveSystemName: "leo.carat.down") + .font(.subheadline.weight(.semibold)) + } + .foregroundColor(Color(.braveBlurpleTint)) + } if nftStore.isLoadingDiscoverAssets && isNFTDiscoveryEnabled { ProgressView() .padding(.leading, 5) } Spacer() - Picker(selection: $nftStore.displayType) { - ForEach(NFTStore.NFTDisplayType.allCases) { type in - Text(type.dropdownTitle) - .foregroundColor(Color(.secondaryBraveLabel)) - .tag(type) - } - } label: { - Text(nftStore.displayType.dropdownTitle) - .font(.footnote) - .foregroundColor(Color(.braveLabel)) - } - filtersButton - .padding(.trailing, 10) addCustomAssetButton + .padding(.trailing, 10) + filtersButton } .padding(.horizontal) .frame(maxWidth: .infinity, alignment: .leading) @@ -236,53 +248,28 @@ struct NFTView: View { EmptyView() } else { WalletDisclosureGroup( + isNFTGroup: true, isExpanded: Binding( get: { groupToggleState[group.id, default: true] }, set: { groupToggleState[group.id] = $0 } ), content: { nftGridsPlainView(group) + .padding(.top) }, label: { if case let .account(account) = group.groupType { AddressView(address: account.address) { - groupHeader(for: group) + PortfolioAssetGroupHeaderView(group: group) } } else { - groupHeader(for: group) + PortfolioAssetGroupHeaderView(group: group) } } ) } } - /// Builds the in-section header for an NFTGroupViewModel that is shown in expanded and non-expanded state. Not used for ungrouped assets. - private func groupHeader(for group: NFTGroupViewModel) -> some View { - VStack(spacing: 0) { - HStack { - if case let .network(networkInfo) = group.groupType { - NetworkIcon(network: networkInfo, length: 32) - } else if case let .account(accountInfo) = group.groupType { - Blockie(address: accountInfo.address, shape: .rectangle) - .frame(width: 32, height: 32) - .clipShape(RoundedRectangle(cornerRadius: 4)) - } - VStack(alignment: .leading) { - Text(group.title) - .font(.callout.weight(.semibold)) - .foregroundColor(Color(WalletV2Design.textPrimary)) - if let description = group.description { - Text(description) - .font(.footnote) - .foregroundColor(Color(WalletV2Design.textSecondary)) - } - } - .multilineTextAlignment(.leading) - } - .padding(.vertical, 4) - } - } - var body: some View { LazyVStack(spacing: 16) { nftHeaderView diff --git a/Sources/BraveWallet/Crypto/Portfolio/PortfolioAssetsView.swift b/Sources/BraveWallet/Crypto/Portfolio/PortfolioAssetsView.swift index ef748929425..967fff09487 100644 --- a/Sources/BraveWallet/Crypto/Portfolio/PortfolioAssetsView.swift +++ b/Sources/BraveWallet/Crypto/Portfolio/PortfolioAssetsView.swift @@ -166,6 +166,7 @@ struct PortfolioAssetsView: View { /// Builds the expandable/collapseable (expanded by default) section content for a given group. @ViewBuilder private func groupedAssetsSection(for group: AssetGroupViewModel) -> some View { WalletDisclosureGroup( + isNFTGroup: false, isExpanded: Binding( get: { groupToggleState[group.id, default: true] }, set: { isExpanded in @@ -196,44 +197,12 @@ struct PortfolioAssetsView: View { label: { if case let .account(account) = group.groupType { AddressView(address: account.address) { - groupHeader(for: group) + PortfolioAssetGroupHeaderView(group: group) } } else { - groupHeader(for: group) + PortfolioAssetGroupHeaderView(group: group) } } ) } - - /// Builds the in-section header for an AssetGroupViewModel that is shown in expanded and non-expanded state. Not used for ungrouped assets. - private func groupHeader(for group: AssetGroupViewModel) -> some View { - VStack(spacing: 0) { - HStack { - if case let .network(networkInfo) = group.groupType { - NetworkIcon(network: networkInfo, length: 32) - } else if case let .account(accountInfo) = group.groupType { - Blockie(address: accountInfo.address, shape: .rectangle) - .frame(width: 32, height: 32) - .clipShape(RoundedRectangle(cornerRadius: 4)) - } - VStack(alignment: .leading) { - Text(group.title) - .font(.callout.weight(.semibold)) - .foregroundColor(Color(WalletV2Design.textPrimary)) - if let description = group.description { - Text(description) - .font(.footnote) - .foregroundColor(Color(WalletV2Design.textSecondary)) - } - } - .multilineTextAlignment(.leading) - Spacer() - Text(isShowingBalances.value ? portfolioStore.currencyFormatter.string(from: NSNumber(value: group.totalFiatValue)) ?? "" : "****") - .font(.callout.weight(.semibold)) - .foregroundColor(Color(WalletV2Design.textPrimary)) - .multilineTextAlignment(.trailing) - } - .padding(.vertical, 4) - } - } } diff --git a/Sources/BraveWallet/Crypto/Portfolio/PortfolioView.swift b/Sources/BraveWallet/Crypto/Portfolio/PortfolioView.swift index 5d6172597b2..645428a7bf2 100644 --- a/Sources/BraveWallet/Crypto/Portfolio/PortfolioView.swift +++ b/Sources/BraveWallet/Crypto/Portfolio/PortfolioView.swift @@ -91,6 +91,37 @@ struct PortfolioView: View { } } +/// Builds the in-section header for `Assets`/`NFT` that is shown in expanded and non-expanded state. Not used for ungrouped assets. +struct PortfolioAssetGroupHeaderView: View { + let group: any WalletAssetGroupViewModel + + var body: some View { + VStack(spacing: 0) { + HStack { + if case let .network(networkInfo) = group.groupType { + NetworkIcon(network: networkInfo, length: 32) + } else if case let .account(accountInfo) = group.groupType { + Blockie(address: accountInfo.address, shape: .rectangle) + .frame(width: 32, height: 32) + .clipShape(RoundedRectangle(cornerRadius: 4)) + } + VStack(alignment: .leading) { + Text(group.title) + .font(.callout.weight(.semibold)) + .foregroundColor(Color(WalletV2Design.textPrimary)) + if let description = group.description { + Text(description) + .font(.footnote) + .foregroundColor(Color(WalletV2Design.textSecondary)) + } + } + .multilineTextAlignment(.leading) + } + .padding(.vertical, 4) + } + } +} + #if DEBUG struct PortfolioViewController_Previews: PreviewProvider { static var previews: some View { diff --git a/Sources/BraveWallet/Crypto/Stores/NFTStore.swift b/Sources/BraveWallet/Crypto/Stores/NFTStore.swift index 21064ba8e25..8328d96339a 100644 --- a/Sources/BraveWallet/Crypto/Stores/NFTStore.swift +++ b/Sources/BraveWallet/Crypto/Stores/NFTStore.swift @@ -163,6 +163,10 @@ public class NFTStore: ObservableObject, WalletObserverStore { return displayNFTGroups.isEmpty } + var totalDisplayNFTCounter: Int { + displayNFTGroups.reduce(0) { $0 + $1.assets.count } + } + public init( keyringService: BraveWalletKeyringService, rpcService: BraveWalletJsonRpcService, @@ -191,6 +195,7 @@ public class NFTStore: ObservableObject, WalletObserverStore { Preferences.Wallet.isHidingUnownedNFTsFilter.observe(from: self) Preferences.Wallet.isShowingNFTNetworkLogoFilter.observe(from: self) Preferences.Wallet.nonSelectedNetworksFilter.observe(from: self) + Preferences.Wallet.groupByFilter.observe(from: self) } func tearDown() { diff --git a/Sources/BraveWallet/Crypto/Stores/PortfolioStore.swift b/Sources/BraveWallet/Crypto/Stores/PortfolioStore.swift index b97031fd62b..d524b1a1554 100644 --- a/Sources/BraveWallet/Crypto/Stores/PortfolioStore.swift +++ b/Sources/BraveWallet/Crypto/Stores/PortfolioStore.swift @@ -353,6 +353,7 @@ public class PortfolioStore: ObservableObject, WalletObserverStore { Preferences.Wallet.isHidingSmallBalancesFilter.observe(from: self) Preferences.Wallet.nonSelectedAccountsFilter.observe(from: self) Preferences.Wallet.nonSelectedNetworksFilter.observe(from: self) + Preferences.Wallet.groupByFilter.observe(from: self) } func tearDown() { diff --git a/Sources/BraveWallet/Crypto/WalletDisclosureGroup.swift b/Sources/BraveWallet/Crypto/WalletDisclosureGroup.swift index c8f8d4ff559..400f2c7679f 100644 --- a/Sources/BraveWallet/Crypto/WalletDisclosureGroup.swift +++ b/Sources/BraveWallet/Crypto/WalletDisclosureGroup.swift @@ -6,6 +6,7 @@ import SwiftUI struct WalletDisclosureGroup: View { + var isNFTGroup: Bool @Binding var isExpanded: Bool @ViewBuilder var content: () -> Content @ViewBuilder var label: () -> Label @@ -44,7 +45,7 @@ struct WalletDisclosureGroup: View { if isExpanded { Divider() .padding(.top, 6) - .padding(.horizontal, 8) + .padding(.horizontal, isNFTGroup ? nil : 8) content() .padding(.horizontal) } @@ -52,10 +53,14 @@ struct WalletDisclosureGroup: View { // when collapsed, padding is applied to `header` .padding(.vertical, isExpanded ? 6 : 0) .osAvailabilityModifiers { - if isExpanded { - $0.overlay { - RoundedRectangle(cornerRadius: 16) - .stroke(Color(braveSystemName: .dividerSubtle), lineWidth: 1) + if !isNFTGroup { + if isExpanded { + $0.overlay { + RoundedRectangle(cornerRadius: 16) + .stroke(Color(braveSystemName: .dividerSubtle), lineWidth: 1) + } + } else { + $0 } } else { $0 diff --git a/Sources/BraveWallet/Extensions/WalletColors.swift b/Sources/BraveWallet/Extensions/WalletColors.swift index b7c57b5d001..1f5e778cce1 100644 --- a/Sources/BraveWallet/Extensions/WalletColors.swift +++ b/Sources/BraveWallet/Extensions/WalletColors.swift @@ -257,4 +257,11 @@ enum WalletV2Design { blue: 207 / 255, alpha: 1 ) + + static let displayNFTCounterColor = UIColor( + red: 213 / 255, + green: 220 / 255, + blue: 1, + alpha: 1 + ) }