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

Token transfer assets elements #502

Merged
merged 16 commits into from
May 19, 2023
25 changes: 25 additions & 0 deletions Sources/Core/DesignSystem/Components/TransferNFTView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
public struct TransferNFTView: View {
let name: String?
let thumbnail: URL?

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

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

if let name {
Text(name)
.textStyle(.body1HighImportance)
.foregroundColor(.app.gray1)
}

Spacer(minLength: 0)
}
.padding(.horizontal, .medium3)
}
}
4 changes: 4 additions & 0 deletions Sources/Core/DesignSystem/Fonts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ extension SwiftUI.Font.App {
body2Header
}

public var body3HighImportance: SwiftUI.Font {
.custom(FontFamily.IBMPlexSans.medium, size: 12)
}

public var button: SwiftUI.Font {
.custom(FontFamily.IBMPlexSans.bold, size: 16)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public enum TextStyle {
case body2HighImportance
case body2Regular
case body2Link
case body3HighImportance
case button
case monospace
}
Expand All @@ -33,6 +34,7 @@ extension TextStyle {
case .body2HighImportance: return .app.body2HighImportance
case .body2Regular: return .app.body2Regular
case .body2Link: return .app.body2Link
case .body3HighImportance: return .app.body3HighImportance
case .button: return .app.button
case .monospace: return .app.monospace
}
Expand All @@ -46,7 +48,7 @@ extension TextStyle {
.body1HighImportance, .body1Regular, .body1StandaloneLink, .body1Link:
return 23 / 4
case .body2Header, .body2HighImportance, .body2Regular,
.body2Link, .button, .monospace:
.body2Link, .body3HighImportance, .button, .monospace:
return 18 / 4
}
}
Expand Down
8 changes: 6 additions & 2 deletions Sources/Core/FeaturePrelude/SmallAccountCard.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,25 @@ import SharedModels
import SwiftUI

// MARK: - SmallAccountCard
public struct SmallAccountCard: View {
public struct SmallAccountCard<Accessory: View>: View {
let name: String
let identifiable: LedgerIdentifiable
let gradient: Gradient
let height: CGFloat
let accessory: Accessory

public init(
_ name: String,
identifiable: LedgerIdentifiable,
gradient: Gradient,
height: CGFloat = .standardButtonHeight
height: CGFloat = .standardButtonHeight,
@ViewBuilder accessory: () -> Accessory = { EmptyView() }
) {
self.name = name
self.identifiable = identifiable
self.gradient = gradient
self.height = height
self.accessory = accessory()
}
}

Expand All @@ -34,6 +37,7 @@ extension SmallAccountCard {
AddressView(identifiable)
.foregroundColor(.app.whiteTransparent)
.textStyle(.body2HighImportance)
accessory
}
.padding(.horizontal, .medium3)
.frame(height: height)
Expand Down
8 changes: 7 additions & 1 deletion Sources/Core/SharedModels/Assets/AccountPortfolio.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ extension AccountPortfolio {

extension AccountPortfolio.NonFungibleResource {
public func nftGlobalID(for id: NonFungibleToken.LocalID) -> GlobalID {
resourceAddress.address + ":" + id.rawValue
resourceAddress.nftGlobalId(id).address
}
}

extension ResourceAddress {
public func nftGlobalId(_ localID: AccountPortfolio.NonFungibleResource.NonFungibleToken.LocalID) -> ResourceAddress {
ResourceAddress(address: address + ":" + localID.rawValue)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ public struct AssetTransfer: Sendable, FeatureReducer {
public var accounts: TransferAccountList.State
public var message: AssetTransferMessage.State?

public var canSendTransferRequest: Bool

public init(from account: Profile.Network.Account) {
self.accounts = .init(fromAccount: account)
self.message = nil
self.canSendTransferRequest = false
}
}

Expand Down Expand Up @@ -58,6 +61,9 @@ public struct AssetTransfer: Sendable, FeatureReducer {
case .message(.delegate(.removed)):
state.message = nil
return .none
case let .accounts(.delegate(.canSendTransferRequest(enabled))):
state.canSendTransferRequest = enabled
return .none
default:
return .none
}
Expand Down
18 changes: 4 additions & 14 deletions Sources/Features/AssetTransferFeature/AssetTransfer+View.swift
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import FeaturePrelude

// MARK: - TransferFocusedField
public enum TransferFocusedField: Hashable {
case message
case asset(accountContainer: ReceivingAccount.State.ID, asset: UUID)
}

extension AssetTransfer {
public typealias ViewState = State

@MainActor
public struct View: SwiftUI.View {
private let store: StoreOf<AssetTransfer>
@FocusState var focusedField: TransferFocusedField?

public init(store: StoreOf<AssetTransfer>) {
self.store = store
Expand All @@ -29,13 +22,12 @@ extension AssetTransfer.View {
IfLetStore(
store.scope(state: \.message, action: { .child(.message($0)) }),
then: {
AssetTransferMessage.View(store: $0, focused: $focusedField)
AssetTransferMessage.View(store: $0)
}
)

TransferAccountList.View(
store: store.scope(state: \.accounts, action: { .child(.accounts($0)) }),
focusedField: $focusedField
store: store.scope(state: \.accounts, action: { .child(.accounts($0)) })
)

FixedSpacer(height: .large1)
Expand All @@ -44,7 +36,7 @@ extension AssetTransfer.View {
viewStore.send(.sendTransferTapped)
}
.buttonStyle(.primaryRectangular)
.controlState(.disabled)
.controlState(viewStore.canSendTransferRequest ? .enabled : .disabled)
}
.padding(.horizontal, .medium3)
.safeAreaInset(edge: .top, alignment: .leading, spacing: 0) {
Expand All @@ -55,10 +47,8 @@ extension AssetTransfer.View {
.padding(.bottom, .medium3)
}
}
.onTapGesture {
focusedField = nil
}
}
.scrollDismissesKeyboard(.interactively)
.showDeveloperDisclaimerBanner()
}

Expand Down
17 changes: 7 additions & 10 deletions Sources/Features/AssetTransferFeature/Common/Style.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ import FeaturePrelude
import SwiftUI

extension View {
func roundedCorners(strokeColor: Color, corners: UIRectCorner) -> some View {
self.modifier { view in
view
.clipShape(RoundedCorners(radius: .small2, corners: corners))
.background(
RoundedCorners(radius: .small2, corners: corners)
.stroke(strokeColor, lineWidth: 1)
)
}
func roundedCorners(strokeColor: Color, corners: UIRectCorner = .allCorners) -> some View {
self
.clipShape(RoundedCorners(radius: .small2, corners: corners))
.background(
RoundedCorners(radius: .small2, corners: corners)
.stroke(strokeColor, lineWidth: 1)
)
}

func topRoundedCorners(strokeColor: Color) -> some View {
Expand All @@ -31,6 +29,5 @@ extension Color {

extension CGFloat {
static let dottedLineHeight: CGFloat = 64.0

public static let transferMessageDefaultHeight: Self = 64
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,9 @@ import FeaturePrelude

public struct AddAsset: Sendable, FeatureReducer {
public struct State: Sendable, Hashable {}

public enum DelegateAction: Equatable, Sendable {
case addFungibleResource(AccountPortfolio.FungibleResource, isXRD: Bool)
case addNonFungibleResource(ResourceAddress, AccountPortfolio.NonFungibleResource.NonFungibleToken)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ extension AssetTransferMessage {
@MainActor
public struct View: SwiftUI.View {
private let store: StoreOf<AssetTransferMessage>
let focused: FocusState<TransferFocusedField?>.Binding

public init(store: StoreOf<AssetTransferMessage>, focused: FocusState<TransferFocusedField?>.Binding) {
@FocusState
private var focused: Bool

public init(store: StoreOf<AssetTransferMessage>) {
self.store = store
self.focused = focused
}
}
}
Expand Down Expand Up @@ -46,20 +47,19 @@ extension AssetTransferMessage.View {
.padding(.medium3)
.topRoundedCorners(strokeColor: .borderColor)

TextEditor(text: viewStore.binding(
get: \.message,
send: {
.messageChanged($0)
}
)
TextEditor(text:
viewStore.binding(
get: \.message,
send: { .messageChanged($0) }
)
)
.focused(focused, equals: .message)
.focused($focused)
.frame(minHeight: .transferMessageDefaultHeight, alignment: .leading)
.padding(.medium3)
.multilineTextAlignment(.leading)
.scrollContentBackground(.hidden) // Remove the default background to allow customization
.background(Color.containerContentBackground)
.bottomRoundedCorners(strokeColor: focused.wrappedValue == .message ? .focusedBorderColor : .borderColor)
.bottomRoundedCorners(strokeColor: focused ? .focusedBorderColor : .borderColor)
}
}
.sheet(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,9 @@ import FeaturePrelude

public struct ChooseAccount: Sendable, FeatureReducer {
public struct State: Sendable, Hashable {}

public enum DelegateAction: Equatable, Sendable {
case addOwnedAccount(Profile.Network.Account)
case addExternalAccount(AccountAddress)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import FeaturePrelude

// MARK: - FungibleResourceAsset
public struct FungibleResourceAsset: Sendable, FeatureReducer {
public struct State: Sendable, Hashable, Identifiable {
public typealias ID = ResourceAddress

public var id: ID {
resource.resourceAddress
}

public var balance: BigDecimal {
resource.amount
}

public var totalExceedsBalance: Bool {
totalTransferSum > balance
}

// Transfered resource
public let resource: AccountPortfolio.FungibleResource
public let isXRD: Bool

// MARK: - Mutable state

public var transferAmountStr: String = ""
public var transferAmount: BigDecimal? = nil

// Total transfer sum for the transferred resource
public var totalTransferSum: BigDecimal

init(resource: AccountPortfolio.FungibleResource, isXRD: Bool, totalTransferSum: BigDecimal) {
self.resource = resource
self.isXRD = isXRD
self.totalTransferSum = totalTransferSum
}
}

public enum ViewAction: Equatable, Sendable {
case amountChanged(String)
case maxAmountTapped
case removeTapped
}

public enum DelegateAction: Equatable, Sendable {
case removed
case amountChanged
}

public func reduce(into state: inout State, viewAction: ViewAction) -> EffectTask<Action> {
switch viewAction {
case let .amountChanged(transferAmountStr):
state.transferAmountStr = transferAmountStr

if let value = try? BigDecimal(localizedFromString: transferAmountStr) {
state.transferAmount = value
} else {
state.transferAmount = nil
}
return .send(.delegate(.amountChanged))

case .maxAmountTapped:
let sumOfOthers = state.totalTransferSum - (state.transferAmount ?? .zero)
let remainingAmount = max(state.balance - sumOfOthers, 0)
GhenadieVP marked this conversation as resolved.
Show resolved Hide resolved
state.transferAmount = remainingAmount
state.transferAmountStr = remainingAmount.droppingTrailingZeros.formatWithoutRounding()
return .send(.delegate(.amountChanged))
GhenadieVP marked this conversation as resolved.
Show resolved Hide resolved

case .removeTapped:
return .send(.delegate(.removed))
GhenadieVP marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Loading