Skip to content

Commit

Permalink
Fix brave/brave-ios#8063: Some V2 updates on under Portfolio/NFT (bra…
Browse files Browse the repository at this point in the history
  • Loading branch information
nuo-xu authored Nov 15, 2023
1 parent e94973e commit ed2864d
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 104 deletions.
2 changes: 2 additions & 0 deletions Sources/BraveWallet/AdjustableHeightAttributedTextView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ struct AttributedTextView: UIViewRepresentable {
$0.delegate = context.coordinator
$0.isScrollEnabled = false
$0.textAlignment = .center
$0.textContainer.lineFragmentPadding = 0
$0.textContainerInset = .zero
}
return textView
}
Expand Down
11 changes: 4 additions & 7 deletions Sources/BraveWallet/Crypto/AssetIconView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ struct NFTIconView: View {
var url: URL?
/// If we should show the network logo on non-native assets
var shouldShowNetworkIcon: Bool = false
/// View is loading NFT metadata
var isLoadingMetadata: Bool = false

@ScaledMetric var length: CGFloat = 40
var maxLength: CGFloat?
Expand All @@ -160,13 +162,8 @@ struct NFTIconView: View {
}

var body: some View {
NFTImageView(urlString: url?.absoluteString ?? "") {
AssetIconView(
token: token,
network: network,
shouldShowNetworkIcon: shouldShowNetworkIcon,
length: length
)
NFTImageView(urlString: url?.absoluteString ?? "", isLoading: isLoadingMetadata) {
LoadingNFTView(shimmer: false)
}
.cornerRadius(5)
.frame(
Expand Down
56 changes: 22 additions & 34 deletions Sources/BraveWallet/Crypto/NFT/NFTDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,11 @@ struct NFTDetailView: View {
}

@ViewBuilder private var nftImage: some View {
if let nftMetadata = nftDetailStore.nftMetadata {
if let urlString = nftMetadata.imageURLString {
NFTImageView(urlString: urlString) {
noImageView
}
.cornerRadius(10)
} else {
noImageView
}
} else {
NFTImageView(urlString: nftDetailStore.nftMetadata?.imageURLString ?? "", isLoading: nftDetailStore.isLoading) {
noImageView
}
.cornerRadius(10)
.frame(maxWidth: .infinity, minHeight: 300)
}

private var isSVGImage: Bool {
Expand All @@ -46,32 +39,27 @@ struct NFTDetailView: View {
ScrollView(.vertical) {
VStack(alignment: .leading, spacing: 24) {
VStack(spacing: 8) {
if nftDetailStore.isLoading {
ProgressView()
.frame(maxWidth: .infinity, minHeight: 300)
} else {
nftImage
.overlay(alignment: .topLeading) {
if nftDetailStore.nft.isSpam {
HStack(spacing: 4) {
Text(Strings.Wallet.nftSpam)
.padding(.vertical, 4)
.padding(.leading, 6)
.foregroundColor(Color(.braveErrorLabel))
Image(braveSystemName: "leo.warning.triangle-outline")
.padding(.vertical, 4)
.padding(.trailing, 6)
.foregroundColor(Color(.braveErrorBorder))
}
.font(.system(size: 13).weight(.semibold))
.background(
Color(uiColor: WalletV2Design.spamNFTLabelBackground)
.cornerRadius(4)
)
.padding(12)
nftImage
.overlay(alignment: .topLeading) {
if nftDetailStore.nft.isSpam {
HStack(spacing: 4) {
Text(Strings.Wallet.nftSpam)
.padding(.vertical, 4)
.padding(.leading, 6)
.foregroundColor(Color(.braveErrorLabel))
Image(braveSystemName: "leo.warning.triangle-outline")
.padding(.vertical, 4)
.padding(.trailing, 6)
.foregroundColor(Color(.braveErrorBorder))
}
.font(.system(size: 13).weight(.semibold))
.background(
Color(uiColor: WalletV2Design.spamNFTLabelBackground)
.cornerRadius(4)
)
.padding(12)
}
}
}
VStack(alignment: .leading, spacing: 8) {
Text(nftDetailStore.nft.nftTokenTitle)
.font(.title3.weight(.semibold))
Expand Down
92 changes: 63 additions & 29 deletions Sources/BraveWallet/Crypto/NFT/NFTView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,36 +75,28 @@ struct NFTView: View {
if let image = nftViewModel.network.nativeTokenLogoImage, nftStore.filters.isShowingNFTNetworkLogo {
Image(uiImage: image)
.resizable()
.frame(width: 20, height: 20)
.padding(4)
.overlay {
Circle()
.stroke(lineWidth: 2)
.foregroundColor(Color(braveSystemName: .containerBackground))
}
.frame(width: 24, height: 24)
}
}

@ViewBuilder private func nftImage(_ nftViewModel: NFTAssetViewModel) -> some View {
Group {
if let urlString = nftViewModel.nftMetadata?.imageURLString {
NFTImageView(urlString: urlString) {
noImageView(nftViewModel)
LoadingNFTView(shimmer: false)
}
} else {
noImageView(nftViewModel)
LoadingNFTView(shimmer: false)
}
}
.overlay(nftLogo(nftViewModel), alignment: .bottomTrailing)
.cornerRadius(4)
}

@ViewBuilder private func noImageView(_ nftViewModel: NFTAssetViewModel) -> some View {
Blockie(address: nftViewModel.token.contractAddress, shape: .rectangle)
.overlay(
Text(nftViewModel.token.symbol.first?.uppercased() ?? "")
.font(.system(size: 80, weight: .bold, design: .rounded))
.foregroundColor(.white)
.shadow(color: .black.opacity(0.3), radius: 2, x: 0, y: 1)
)
.aspectRatio(1.0, contentMode: .fit)
}

private var filtersButton: some View {
AssetButton(braveSystemName: "leo.filter.settings", action: {
isPresentingFiltersDisplaySettings = true
Expand All @@ -122,18 +114,21 @@ struct NFTView: View {
}
}
.pickerStyle(.inline)
.disabled(nftStore.isShowingNFTLoadingState)
} label: {
HStack(spacing: 12) {
Text(nftStore.displayType.dropdownTitle)
.font(.subheadline.weight(.semibold))
Text("\(nftStore.totalDisplayedNFTCount)")
.padding(.horizontal, 8)
.padding(.vertical, 4)
.font(.caption2.weight(.semibold))
.background(
Color(braveSystemName: .primary20)
.cornerRadius(4)
)
if !nftStore.isShowingNFTLoadingState {
Text("\(nftStore.totalDisplayedNFTCount)")
.padding(.horizontal, 8)
.padding(.vertical, 4)
.font(.caption2.weight(.semibold))
.background(
Color(braveSystemName: .primary20)
.cornerRadius(4)
)
}
Image(braveSystemName: "leo.carat.down")
.font(.subheadline.weight(.semibold))
}
Expand All @@ -146,7 +141,9 @@ struct NFTView: View {
Spacer()
addCustomAssetButton
.padding(.trailing, 10)
.disabled(nftStore.isShowingNFTLoadingState)
filtersButton
.disabled(nftStore.isShowingNFTLoadingState)
}
.padding(.horizontal)
.frame(maxWidth: .infinity, alignment: .leading)
Expand All @@ -161,7 +158,7 @@ struct NFTView: View {
private var nftDiscoveryDescriptionText: NSAttributedString? {
let attributedString = NSMutableAttributedString(
string: Strings.Wallet.nftDiscoveryCalloutDescription,
attributes: [.foregroundColor: UIColor.braveLabel, .font: UIFont.preferredFont(for: .subheadline, weight: .regular)]
attributes: [.foregroundColor: UIColor.secondaryBraveLabel, .font: UIFont.preferredFont(for: .subheadline, weight: .regular)]
)

attributedString.addAttributes([.underlineStyle: NSUnderlineStyle.single.rawValue], range: (attributedString.string as NSString).range(of: "SimpleHash")) // `SimpleHash` won't get translated
Expand All @@ -183,6 +180,10 @@ struct NFTView: View {
}) {
VStack(alignment: .leading, spacing: 4) {
nftImage(nft)
.overlay(alignment: .bottomTrailing) {
nftLogo(nft)
.offset(y: 12)
}
.padding(.bottom, 8)
Text(nft.token.nftTokenTitle)
.font(.callout.weight(.medium))
Expand Down Expand Up @@ -273,7 +274,9 @@ struct NFTView: View {
var body: some View {
LazyVStack(spacing: 16) {
nftHeaderView
if nftStore.isShowingNFTEmptyState {
if nftStore.isShowingNFTLoadingState {
SkeletonLoadingNFTView()
} else if nftStore.isShowingNFTEmptyState {
emptyView
} else {
ForEach(nftStore.displayNFTGroups) { group in
Expand Down Expand Up @@ -334,10 +337,9 @@ struct NFTView: View {
),
showCloseButton: false,
content: {
VStack(spacing: 10) {
VStack(alignment: .leading, spacing: 10) {
Text(Strings.Wallet.nftDiscoveryCalloutTitle)
.font(.headline.weight(.bold))
.multilineTextAlignment(.center)
.font(.body.weight(.medium))
if let attrString = nftDiscoveryDescriptionText {
AdjustableHeightAttributedTextView(
attributedString: attrString,
Expand All @@ -349,6 +351,7 @@ struct NFTView: View {
)
}
}
.padding(.bottom, 24)
}
)
)
Expand Down Expand Up @@ -382,6 +385,8 @@ struct NFTView: View {
.font(.footnote)
.foregroundStyle(Color(.secondaryBraveLabel))
}
.multilineTextAlignment(.center)
.padding(.bottom, 24)
})
)
.sheet(isPresented: $isShowingAddCustomNFT) {
Expand Down Expand Up @@ -427,6 +432,35 @@ struct NFTView: View {
}
}

struct SkeletonLoadingNFTView: View {

private let nftGrids = [GridItem(.adaptive(minimum: 160), spacing: 16, alignment: .top)]

var body: some View {
LazyVGrid(columns: nftGrids) {
ForEach(0..<6) { _ in
VStack(alignment: .leading, spacing: 6) {
LoadingNFTView()
.frame(height: 176)
Group {
Color(braveSystemName: .containerHighlight)
.frame(width: 148, height: 12)
Color(braveSystemName: .containerHighlight)
.frame(width: 96, height: 12)
}
.clipShape(Capsule())
.redacted(reason: .placeholder)
.shimmer(true)
}
.padding(.horizontal, 8)
.padding(.top, 8)
.padding(.bottom, 24)
.accessibilityHidden(true)
}
}
}
}

#if DEBUG
struct NFTView_Previews: PreviewProvider {
static var previews: some View {
Expand Down
75 changes: 54 additions & 21 deletions Sources/BraveWallet/Crypto/NFTImageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,24 @@ import SDWebImageSwiftUI
struct NFTImageView<Placeholder: View>: View {
private let urlString: String
private var placeholder: () -> Placeholder
var isLoading: Bool

init(
urlString: String,
isLoading: Bool = false,
@ViewBuilder placeholder: @escaping () -> Placeholder
) {
self.urlString = urlString
self.isLoading = isLoading
self.placeholder = placeholder
}

var body: some View {
if let url = URL(string: urlString) {
if url.absoluteString.hasPrefix("data:image/") {
WebImageReader(url: url) { image in
if let image = image {
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
} else {
placeholder()
}
}
} else if url.isSecureWebPage() {
if url.absoluteString.hasSuffix(".gif") {
WebImage(url: url)
.resizable()
.placeholder { placeholder() }
.indicator(.activity)
.aspectRatio(contentMode: .fit)
} else {
if isLoading {
LoadingNFTView()
} else {
if let url = URL(string: urlString) {
if url.absoluteString.hasPrefix("data:image/") {
WebImageReader(url: url) { image in
if let image = image {
Image(uiImage: image)
Expand All @@ -48,12 +37,56 @@ struct NFTImageView<Placeholder: View>: View {
placeholder()
}
}
} else if url.isSecureWebPage() {
if url.absoluteString.hasSuffix(".gif") {
WebImage(url: url)
.resizable()
.placeholder { placeholder() }
.indicator(.activity)
.aspectRatio(contentMode: .fit)
} else {
WebImageReader(url: url) { image in
if let image = image {
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fit)
} else {
placeholder()
}
}
}
} else {
placeholder()
}
} else {
placeholder()
}
} else {
placeholder()
}
}
}

struct LoadingNFTView: View {
var shimmer: Bool = true
@State var viewSize: CGSize = .zero
var body: some View {
Color(braveSystemName: .containerHighlight)
.cornerRadius(4)
.redacted(reason: .placeholder)
.shimmer(shimmer)
.overlay {
Image(braveSystemName: "leo.nft")
.foregroundColor(Color(braveSystemName: .containerBackground))
.font(.system(size: floor(viewSize.width / 3)))
}
.background(
GeometryReader { geometryProxy in
Color.clear
.preference(key: SizePreferenceKey.self, value: geometryProxy.size)
}
)
.frame(minHeight: viewSize.width)
.onPreferenceChange(SizePreferenceKey.self) { newSize in
viewSize = newSize
}
}
}
Loading

0 comments on commit ed2864d

Please sign in to comment.