diff --git a/AlphaWallet/Tokens/Views/OpenSea/OpenSeaNonFungibleTokenViewCell.swift b/AlphaWallet/Tokens/Views/OpenSea/OpenSeaNonFungibleTokenViewCell.swift index a076ac307..b45f05da7 100644 --- a/AlphaWallet/Tokens/Views/OpenSea/OpenSeaNonFungibleTokenViewCell.swift +++ b/AlphaWallet/Tokens/Views/OpenSea/OpenSeaNonFungibleTokenViewCell.swift @@ -5,11 +5,30 @@ import UIKit class OpenSeaNonFungibleTokenView: UIView { private let background = UIView() - private let imageView = TokenImageView(scale: .bestFill) + private let imageView: TokenImageView = { + let imageView: TokenImageView = TokenImageView(scale: .bestFill) + imageView.isRoundingEnabled = false + imageView.isChainOverlayHidden = true + imageView.translatesAutoresizingMaskIntoConstraints = false + + return imageView + }() //Holder so UIMotionEffect don't reveal the background behind the image private let imageHolder = UIView() - private let label = UILabel() - private let countLabel = UILabel() + private let label: UILabel = { + let label = UILabel() + label.setContentHuggingPriority(.required, for: .vertical) + label.setContentCompressionResistancePriority(.required, for: .vertical) + + return label + }() + private let countLabel: UILabel = { + let countLabel = UILabel() + countLabel.setContentHuggingPriority(.required, for: .vertical) + countLabel.setContentCompressionResistancePriority(.required, for: .vertical) + + return countLabel + }() private var tokenAddress: AlphaWallet.Address? override init(frame: CGRect) { @@ -17,6 +36,7 @@ class OpenSeaNonFungibleTokenView: UIView { background.translatesAutoresizingMaskIntoConstraints = false addSubview(background) + let textsStackView = [ label, countLabel, @@ -29,11 +49,8 @@ class OpenSeaNonFungibleTokenView: UIView { .spacer(height: 8), ].asStackView(axis: .vertical, spacing: 0, alignment: .fill) stackView.translatesAutoresizingMaskIntoConstraints = false + background.addSubview(stackView) - imageView.isRoundingEnabled = false - imageView.isChainOverlayHidden = true - - imageView.translatesAutoresizingMaskIntoConstraints = false imageHolder.addSubview(imageView) NSLayoutConstraint.activate([ @@ -42,6 +59,7 @@ class OpenSeaNonFungibleTokenView: UIView { stackView.anchorsConstraint(to: background), imageView.anchorsConstraint(to: imageHolder) ]) + translatesAutoresizingMaskIntoConstraints = false } diff --git a/AlphaWallet/UI/TokenObject+UI.swift b/AlphaWallet/UI/TokenObject+UI.swift index 401ff7aff..593e6841a 100644 --- a/AlphaWallet/UI/TokenObject+UI.swift +++ b/AlphaWallet/UI/TokenObject+UI.swift @@ -152,17 +152,17 @@ class TokenImageFetcher { let queue = self.queue let subscribable: Subscribable let key = "\(contractAddress.eip55String)-\(server.chainID)" - if let sub = Self.subscribables[key] { + if let sub = TokenImageFetcher.subscribables[key] { subscribable = sub if let value = sub.value, value.isFinal { return subscribable } } else { let sub = Subscribable(getDefaultOrGenerateIcon()) - Self.subscribables[key] = sub + TokenImageFetcher.subscribables[key] = sub subscribable = sub } - + func getDefaultOrGenerateIcon() -> TokenImage? { switch type { case .nativeCryptocurrency: @@ -175,7 +175,7 @@ class TokenImageFetcher { } } - return Self.programmaticallyGenerateIcon(for: contractAddress, type: type, server: server, symbol: name) + return TokenImageFetcher.programmaticallyGenerateIcon(for: contractAddress, type: type, server: server, symbol: name) } if contractAddress.sameContract(as: Constants.nativeCryptoAddressInDatabase) { @@ -198,37 +198,51 @@ class TokenImageFetcher { } } - Self.fetchFromOpenSea(type, balance: balance, queue: queue).done(on: .main, { - subscribable.value = (image: $0, symbol: "", isFinal: true, overlayServerIcon: server.staticOverlayIcon) - }).catch(on: queue) { _ in - Self.fetchFromAssetGitHubRepo(contractAddress: contractAddress, queue: queue).done(on: .main, { - subscribable.value = (image: .image($0), symbol: "", isFinal: false, overlayServerIcon: server.staticOverlayIcon) - }).catch(on: .main, { _ in - subscribable.value = generatedImage - }) - } + if let image = generatedImage, image.isFinal { + return + } + + firstly { + TokenImageFetcher + .fetchFromAssetGitHubRepo(.alphaWallet, contractAddress: contractAddress, queue: queue) + .map(on: queue, { image -> TokenImage in + return (image: .image(image), symbol: "", isFinal: true, overlayServerIcon: server.staticOverlayIcon) + }) + }.recover(on: queue, { _ -> Promise in + return TokenImageFetcher + .fetchFromOpenSea(type, balance: balance, queue: queue) + .map(on: queue, { url -> TokenImage in + return (image: url, symbol: "", isFinal: true, overlayServerIcon: server.staticOverlayIcon) + }) + }).recover(on: queue, { _ -> Promise in + return TokenImageFetcher + .fetchFromAssetGitHubRepo(.thirdParty, contractAddress: contractAddress, queue: queue) + .map(on: queue, { image -> TokenImage in + return (image: .image(image), symbol: "", isFinal: false, overlayServerIcon: server.staticOverlayIcon) + }) + }).done(on: .main, { value in + subscribable.value = value + }).catch(on: .main, { _ in + subscribable.value = generatedImage + }) } return subscribable } private static func fetchFromOpenSea(_ type: TokenType, balance: String?, queue: DispatchQueue) -> Promise { - Promise { seal in - queue.async { - switch type { - case .erc721, .erc1155: - if let json = balance, let data = json.data(using: .utf8), let openSeaNonFungible = nonFungible(fromJsonData: data) { - guard let url = URL(string: openSeaNonFungible.contractImageUrl) ?? URL(string: openSeaNonFungible.thumbnailUrl) else { - return seal.reject(ImageAvailabilityError.notAvailable) - } - return seal.fulfill(.url(url)) - } else { - seal.reject(ImageAvailabilityError.notAvailable) - } - case .nativeCryptocurrency, .erc20, .erc875, .erc721ForTickets: - seal.reject(ImageAvailabilityError.notAvailable) + switch type { + case .erc721, .erc1155: + if let json = balance, let data = json.data(using: .utf8), let openSeaNonFungible = nonFungible(fromJsonData: data) { + guard let url = URL(string: openSeaNonFungible.contractImageUrl) ?? URL(string: openSeaNonFungible.thumbnailUrl) else { + return .init(error: ImageAvailabilityError.notAvailable) } + return .value(.url(url)) + } else { + return .init(error: ImageAvailabilityError.notAvailable) } + case .nativeCryptocurrency, .erc20, .erc875, .erc721ForTickets: + return .init(error: ImageAvailabilityError.notAvailable) } } @@ -240,22 +254,14 @@ class TokenImageFetcher { }) } - private static func fetchFromAssetGitHubRepo(contractAddress: AlphaWallet.Address, queue: DispatchQueue) -> Promise { - firstly { - fetchFromAssetGitHubRepo(.alphaWallet, contractAddress: contractAddress, queue: queue) - }.recover(on: queue, { _ -> Promise in - fetchFromAssetGitHubRepo(.thirdParty, contractAddress: contractAddress, queue: queue) - }) - } - private static func fetch(request: URLRequest, queue: DispatchQueue) -> Promise { - Alamofire.request(request).responseData().map(on: queue) { response -> UIImage in + return Alamofire.request(request).responseData(queue: queue).map(on: queue, { response -> UIImage in if let img = UIImage(data: response.data) { return img } else { throw ImageAvailabilityError.notAvailable } - }.recover { error -> Promise in + }).recover(on: queue, { error -> Promise in //This is expected. Some tokens will not have icons if let url = request.url?.absoluteString { verboseLog("Loading token icon URL: \(url) error") @@ -263,7 +269,7 @@ class TokenImageFetcher { verboseLog("Loading token icon URL: nil error") } throw error - } + }) } }