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

ABW-1813 Display NFTs properly #587

Merged
merged 5 commits into from
Jun 21, 2023
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,7 @@ extension AccountPortfoliosClient {
let tokens = try await gatewayAPIClient.getNonFungibleData(.init(
resourceAddress: resource.resourceAddress,
nonFungibleIds: Array(nftIDChunk)
)
)
))
.nonFungibleIds
.map {
AccountPortfolio.NonFungibleResource.NonFungibleToken(
Expand Down Expand Up @@ -313,24 +312,6 @@ extension AccountPortfoliosClient {
}
}

// FIXME: Temporary hack to extract the key_image_url, until we have a proper schema
private extension GatewayAPI.StateNonFungibleDetailsResponseItem {
var keyImageURL: URL? {
guard let dictionary = mutableData.rawJson.value as? [String: Any] else { return nil }
guard let elements = dictionary["elements"] as? [[String: Any]] else { return nil }
let values = elements.filter { $0["type"] as? String == "String" }.compactMap { $0["value"] as? String }
let extensions = ["jpg", "jpeg", "png", "pdf", "svg", "gif"]
for value in values {
for ext in extensions {
if value.lowercased().hasSuffix(ext) {
return .init(string: value)
}
}
}
return nil
}
}

// MARK: - Endpoints
extension AccountPortfoliosClient {
static func fetchAccountFungibleResourcePage(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,21 @@ extension GatewayAPI.EntityMetadataCollection {
return self
}
}

// FIXME: Temporary hack to extract the key_image_url, until we have a proper schema
extension GatewayAPI.StateNonFungibleDetailsResponseItem {
public var keyImageURL: URL? {
guard let dictionary = mutableData.rawJson.value as? [String: Any] else { return nil }
guard let elements = dictionary["elements"] as? [[String: Any]] else { return nil }
let values = elements.filter { $0["type"] as? String == "String" }.compactMap { $0["value"] as? String }
let extensions = ["jpg", "jpeg", "png", "pdf", "svg", "gif"]
for value in values {
for ext in extensions {
if value.lowercased().hasSuffix(ext) {
return .init(string: value)
}
}
}
return nil
}
}
40 changes: 30 additions & 10 deletions Sources/Core/DesignSystem/Components/TransferNFTView.swift
Original file line number Diff line number Diff line change
@@ -1,25 +1,45 @@
// MARK: - TransferNFTView
public struct TransferNFTView: View {
let name: String?
let thumbnail: URL?
public let viewState: ViewState

public init(name: String?, thumbnail: URL?) {
self.name = name
self.thumbnail = thumbnail
public init(viewState: ViewState) {
self.viewState = viewState
}

public var body: some View {
HStack(spacing: .small1) {
NFTThumbnail(thumbnail, size: .small)
NFTThumbnail(viewState.thumbnail, size: .small)
.padding(.vertical, .small1)

if let name {
Text(name)
.textStyle(.body1HighImportance)
.foregroundColor(.app.gray1)
VStack(alignment: .leading, spacing: 0) {
Text(viewState.tokenID)
.textStyle(.body2Regular)
.foregroundColor(.app.gray2)

if let tokenName = viewState.tokenName {
Text(tokenName)
.textStyle(.body1HighImportance)
.foregroundColor(.app.gray1)
}
}

Spacer(minLength: 0)
}
.padding(.horizontal, .medium3)
}
}

// MARK: TransferNFTView.ViewState
extension TransferNFTView {
public struct ViewState: Equatable {
public let tokenID: String
public let tokenName: String?
public let thumbnail: URL?

public init(tokenID: String, tokenName: String?, thumbnail: URL?) {
self.tokenID = tokenID
self.tokenName = tokenName
self.thumbnail = thumbnail
}
}
}
15 changes: 7 additions & 8 deletions Sources/Core/SharedModels/Assets/AccountPortfolio.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,17 +134,16 @@ extension ResourceAddress {
}
}

extension AccountPortfolio.NonFungibleResource.NonFungibleToken {
public var userFacingID: String {
let rawValue = id.rawValue

extension String {
/// Creates a user facing string for a local non fungible ID
public var userFacingNonFungibleLocalID: String {
// Just a safety guard. Each NFT Id should be of format <prefix>value<suffix>
guard rawValue.count >= 3 else {
loggerGlobal.warning("Invalid nft id: \(rawValue)")
return rawValue
guard count >= 3 else {
loggerGlobal.warning("Invalid nft id: \(self)")
return self
}
// Nothing fancy, just remove the prefix and suffix.
return String(rawValue.dropLast().dropFirst())
return String(dropLast().dropFirst())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,9 @@ public struct AssetTransfer: Sendable, FeatureReducer {
}

public var body: some ReducerProtocolOf<Self> {
Scope(state: \.accounts,
action: /Action.child .. ChildAction.accounts,
child: { TransferAccountList() })

Scope(state: \.accounts, action: /Action.child .. ChildAction.accounts) {
TransferAccountList()
}
Reduce(core)
.ifLet(\.message, action: /Action.child .. ChildAction.message) {
AssetTransferMessage()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import ChooseAccountsFeature
import EngineToolkitClient
import FeaturePrelude
import ScanQRFeature

Expand Down Expand Up @@ -64,8 +63,6 @@ public struct ChooseReceivingAccount: Sendable, FeatureReducer {
}
}

@Dependency(\.engineToolkitClient) var engineToolkitClient

public init() {}

public var body: some ReducerProtocolOf<Self> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ public struct NonFungibleResourceAsset: Sendable, FeatureReducer {
resourceAddress.nftGlobalId(nftToken.id)
}

public let resourceImage: URL?
public let resourceName: String?
public let resourceAddress: ResourceAddress
public let nftToken: AccountPortfolio.NonFungibleResource.NonFungibleToken
}
}

extension NonFungibleResourceAsset {
public typealias ViewState = State
public typealias ViewState = TransferNFTView.ViewState

@MainActor
public struct View: SwiftUI.View {
Expand All @@ -25,14 +27,21 @@ extension NonFungibleResourceAsset {
}
}

extension NonFungibleResourceAsset.State {
var viewState: NonFungibleResourceAsset.ViewState {
.init(
tokenID: nftToken.id.rawValue.userFacingNonFungibleLocalID,
tokenName: nftToken.name,
thumbnail: resourceImage
)
}
}

extension NonFungibleResourceAsset.View {
public var body: some View {
WithViewStore(store, observe: { $0 }) { viewStore in
TransferNFTView(
name: viewStore.nftToken.userFacingID,
thumbnail: viewStore.nftToken.keyImageURL
)
.frame(height: .largeButtonHeight)
WithViewStore(store, observe: \.viewState) { viewStore in
TransferNFTView(viewState: viewStore.state)
.frame(height: .largeButtonHeight)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,9 @@ public struct TransferAccountList: Sendable, FeatureReducer {
didSet {
if receivingAccounts.count > 1, receivingAccounts[0].canBeRemoved == false {
receivingAccounts[0].canBeRemoved = true
}

if receivingAccounts.count == 1, receivingAccounts[0].canBeRemoved == true {
} else if receivingAccounts.count == 1, receivingAccounts[0].canBeRemoved == true {
receivingAccounts[0].canBeRemoved = false
}

if receivingAccounts.isEmpty {
} else if receivingAccounts.isEmpty {
receivingAccounts.append(.empty(canBeRemovedWhenEmpty: false))
}
}
Expand Down Expand Up @@ -188,7 +184,12 @@ extension TransferAccountList {

assets += selectedAssets.nonFungibleResources.flatMap { resource in
resource.tokens.map {
ResourceAsset.State.nonFungibleAsset(.init(resourceAddress: resource.resourceAddress, nftToken: $0))
ResourceAsset.State.nonFungibleAsset(.init(
resourceImage: resource.resourceImage,
resourceName: resource.resourceName,
resourceAddress: resource.resourceAddress,
nftToken: $0
))
}
}

Expand Down Expand Up @@ -236,6 +237,8 @@ extension TransferAccountList {
.reduce(into: IdentifiedArrayOf<AssetsView.State.Mode.SelectedAssets.NonFungibleTokensPerResource>()) { partialResult, asset in
var resource = partialResult[id: asset.resourceAddress] ?? .init(
resourceAddress: asset.resourceAddress,
resourceImage: asset.resourceImage,
resourceName: asset.resourceName,
tokens: []
)
resource.tokens.append(asset.nftToken)
Expand Down
12 changes: 10 additions & 2 deletions Sources/Features/AssetsFeature/AssetsView+Reducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public struct AssetsView: Sendable, FeatureReducer {
}

@Dependency(\.accountPortfoliosClient) var accountPortfoliosClient

public init() {}

public var body: some ReducerProtocolOf<Self> {
Expand Down Expand Up @@ -159,11 +160,12 @@ extension AssetsView.State {

let nonFungibleResources = nonFungibleTokenList.rows.compactMap {
if let selectedAssets = $0.selectedAssets, !selectedAssets.isEmpty {
let selected = $0.resource.tokens.filter { token in selectedAssets.contains(token.id)
}
let selected = $0.resource.tokens.filter { token in selectedAssets.contains(token.id) }

return Mode.SelectedAssets.NonFungibleTokensPerResource(
resourceAddress: $0.resource.resourceAddress,
resourceImage: $0.resource.iconURL,
resourceName: $0.resource.name,
tokens: selected
)
}
Expand Down Expand Up @@ -204,13 +206,19 @@ extension AssetsView.State {
}

public let resourceAddress: ResourceAddress
public let resourceImage: URL?
public let resourceName: String?
public var tokens: IdentifiedArrayOf<AccountPortfolio.NonFungibleResource.NonFungibleToken>

public init(
resourceAddress: ResourceAddress,
resourceImage: URL?,
resourceName: String?,
tokens: IdentifiedArrayOf<AccountPortfolio.NonFungibleResource.NonFungibleToken>
) {
self.resourceAddress = resourceAddress
self.resourceImage = resourceImage
self.resourceName = resourceName
self.tokens = tokens
}
}
Expand Down
Loading