Skip to content

Commit

Permalink
MOB-1905 - UI for token amount input (#453)
Browse files Browse the repository at this point in the history
* Updated receive button place. Removed current profile switcher.
Added send button

* Updated home screen title view

* Added send crypto view.
Show from the home view.
Added input field and scan qr option

* Added section with user's wallets

* Added send crypto view model
Added UI for following selection

* Refactoring

* Updated nav bar customisation

* Disable interactive dismiss when navigate

* Extracted tab selection view from explore module

* Refactoring

* Created UI for token balance

* Make tokens selectable

* Added UI for domains list in assets selection
Adjusted navigation header UI

* Created senc crypto flow actions
Handle actions in view model
Hide empty sections on receiver selection screen

* Pass actions from select receiver and asset type views

* Refactoring

* Fixed initial onAppear call in token icons view

* Created UDNumberButtonView

* Created number pad view and input interpreter.
Created tests for interpreter

* Improved number pad logic

* Added UI for input and token info

* Added converted value label and toggle

* Added confirmation button

* Refactoring

* Disable animation for primary input view

* Swap buy and send actions on home screen

* Fixed copy on select receiver screen

* Added token icon near primary input value

* Adjusted UI for nav bar and in the IP SE
  • Loading branch information
Oleg-Pecheneg authored Mar 21, 2024
1 parent 9ccc5bf commit 071002f
Show file tree
Hide file tree
Showing 20 changed files with 720 additions and 134 deletions.
42 changes: 42 additions & 0 deletions unstoppable-ios-app/domains-manager-ios.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,17 @@
C62900E92BAAB6F6008B35A2 /* SelectCryptoAssetToSendDomainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62900E72BAAB6F6008B35A2 /* SelectCryptoAssetToSendDomainView.swift */; };
C62900EB2BAAC135008B35A2 /* NavigationTopSafeAreaOffset.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62900EA2BAAC135008B35A2 /* NavigationTopSafeAreaOffset.swift */; };
C62900EC2BAAC135008B35A2 /* NavigationTopSafeAreaOffset.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62900EA2BAAC135008B35A2 /* NavigationTopSafeAreaOffset.swift */; };
C62900EE2BAAC5C0008B35A2 /* BalanceTokenIconsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62900ED2BAAC5C0008B35A2 /* BalanceTokenIconsView.swift */; };
C62900EF2BAAC5C0008B35A2 /* BalanceTokenIconsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62900ED2BAAC5C0008B35A2 /* BalanceTokenIconsView.swift */; };
C62900F52BAAC83A008B35A2 /* SelectTokenAssetAmountToSendView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62900F42BAAC83A008B35A2 /* SelectTokenAssetAmountToSendView.swift */; };
C62900F62BAAC83A008B35A2 /* SelectTokenAssetAmountToSendView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62900F42BAAC83A008B35A2 /* SelectTokenAssetAmountToSendView.swift */; };
C62900F82BAAC922008B35A2 /* UDNumberButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62900F72BAAC922008B35A2 /* UDNumberButtonView.swift */; };
C62900F92BAAC922008B35A2 /* UDNumberButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62900F72BAAC922008B35A2 /* UDNumberButtonView.swift */; };
C62900FB2BAACCD2008B35A2 /* UDNumberPadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62900FA2BAACCD2008B35A2 /* UDNumberPadView.swift */; };
C62900FC2BAACCD2008B35A2 /* UDNumberPadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62900FA2BAACCD2008B35A2 /* UDNumberPadView.swift */; };
C62900FE2BAAD126008B35A2 /* NumberPadInputInterpreterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62900FD2BAAD126008B35A2 /* NumberPadInputInterpreterTests.swift */; };
C62901002BAAD3C3008B35A2 /* NumberPadInputInterpreter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62900FF2BAAD3C3008B35A2 /* NumberPadInputInterpreter.swift */; };
C62901012BAAD3C3008B35A2 /* NumberPadInputInterpreter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62900FF2BAAD3C3008B35A2 /* NumberPadInputInterpreter.swift */; };
C629A4602A3FF13600A528A1 /* MessagingChatMessageImageBase64TypeDisplayInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = C629A45F2A3FF13600A528A1 /* MessagingChatMessageImageBase64TypeDisplayInfo.swift */; };
C629A4802A403C1C00A528A1 /* MessagingChatConversationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C629A47F2A403C1C00A528A1 /* MessagingChatConversationState.swift */; };
C62BDA412B5E4104008E21AD /* MessagingBlockUserInChatType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C62BDA402B5E4104008E21AD /* MessagingBlockUserInChatType.swift */; };
Expand Down Expand Up @@ -2919,6 +2930,12 @@
C62900E42BAAB6E8008B35A2 /* SelectCryptoAssetToSendTokenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectCryptoAssetToSendTokenView.swift; sourceTree = "<group>"; };
C62900E72BAAB6F6008B35A2 /* SelectCryptoAssetToSendDomainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectCryptoAssetToSendDomainView.swift; sourceTree = "<group>"; };
C62900EA2BAAC135008B35A2 /* NavigationTopSafeAreaOffset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationTopSafeAreaOffset.swift; sourceTree = "<group>"; };
C62900ED2BAAC5C0008B35A2 /* BalanceTokenIconsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BalanceTokenIconsView.swift; sourceTree = "<group>"; };
C62900F42BAAC83A008B35A2 /* SelectTokenAssetAmountToSendView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectTokenAssetAmountToSendView.swift; sourceTree = "<group>"; };
C62900F72BAAC922008B35A2 /* UDNumberButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UDNumberButtonView.swift; sourceTree = "<group>"; };
C62900FA2BAACCD2008B35A2 /* UDNumberPadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UDNumberPadView.swift; sourceTree = "<group>"; };
C62900FD2BAAD126008B35A2 /* NumberPadInputInterpreterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberPadInputInterpreterTests.swift; sourceTree = "<group>"; };
C62900FF2BAAD3C3008B35A2 /* NumberPadInputInterpreter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberPadInputInterpreter.swift; sourceTree = "<group>"; };
C629A45F2A3FF13600A528A1 /* MessagingChatMessageImageBase64TypeDisplayInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagingChatMessageImageBase64TypeDisplayInfo.swift; sourceTree = "<group>"; };
C629A47F2A403C1C00A528A1 /* MessagingChatConversationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagingChatConversationState.swift; sourceTree = "<group>"; };
C62BDA402B5E4104008E21AD /* MessagingBlockUserInChatType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagingBlockUserInChatType.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4076,6 +4093,7 @@
C6AB383D2A692D45003C0944 /* PushMessagingAPIServiceTests.swift */,
C63391772A86819600623188 /* XMTPMessagingAPIServiceTests.swift */,
30C0F94927D8CB250060D283 /* PrivateKeyStorageTests.swift */,
C62900FD2BAAD126008B35A2 /* NumberPadInputInterpreterTests.swift */,
29EDB622290A94E700A0BD08 /* ProfilesTests.swift */,
30F526452785BB22004C7AB6 /* ResolutionInitTests.swift */,
308B1D4025B8A75D005FE726 /* testUpdateRecords.swift */,
Expand Down Expand Up @@ -5216,6 +5234,14 @@
path = LayoutHelper;
sourceTree = "<group>";
};
C62900F32BAAC821008B35A2 /* SelectTokenAssetAmount */ = {
isa = PBXGroup;
children = (
C62900F42BAAC83A008B35A2 /* SelectTokenAssetAmountToSendView.swift */,
);
path = SelectTokenAssetAmount;
sourceTree = "<group>";
};
C62C3F94283F35730094FC93 /* CodeVerificationView */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -6276,6 +6302,7 @@
C67213DE2BAA96170075B9C7 /* SendCryptoAssetNavigationDestination.swift */,
C67213CD2BAA80670075B9C7 /* SelectReceiver */,
C67213E72BAA98EC0075B9C7 /* SelectAssetToSend */,
C62900F32BAAC821008B35A2 /* SelectTokenAssetAmount */,
);
path = SendCryptoAsset;
sourceTree = "<group>";
Expand Down Expand Up @@ -7237,6 +7264,7 @@
C63414D92A7D335100C80B77 /* GlobalRR.swift */,
30BA2B35252914100097817E /* Helpers.swift */,
C6B65F962B566B37006D1812 /* NFTDisplayInfo.swift */,
C62900FF2BAAD3C3008B35A2 /* NumberPadInputInterpreter.swift */,
C6ED320C295E8EDE00BC6919 /* NonEmptyArray.swift */,
C671E3AB28FEE72B00A2B3A0 /* UnstoppableImagePicker.swift */,
C61DB11A2B95BD1200CDA243 /* DomainProfileDisplayInfo.swift */,
Expand Down Expand Up @@ -7694,6 +7722,7 @@
C63F1CFE28AD099C000A5C12 /* EmptyRootCNavigationController.swift */,
C6098314282B6F7000546392 /* EmptyRootNavigationController.swift */,
C62247A4283B92C0002A0CBD /* UDNavigationController.swift */,
C62900ED2BAAC5C0008B35A2 /* BalanceTokenIconsView.swift */,
C6B65F4D2B54DA6D006D1812 /* Home */,
C60982A7282A724400546392 /* AddWallet */,
C6386835285C0EB3000F98C4 /* AppUpdatedRequired */,
Expand Down Expand Up @@ -7785,6 +7814,8 @@
children = (
C6DDF24B2B147F1A006D1F0B /* ControllableButtonStyle.swift */,
C6DDF24A2B147F1A006D1F0B /* UDButtonImage.swift */,
C62900FA2BAACCD2008B35A2 /* UDNumberPadView.swift */,
C62900F72BAAC922008B35A2 /* UDNumberButtonView.swift */,
C6DDF2442B147F1A006D1F0B /* UDButtonView */,
C6DDF2472B147F1A006D1F0B /* UDIconButtonView */,
);
Expand Down Expand Up @@ -8701,6 +8732,7 @@
C6C995C6289D313D00367362 /* CBaseTransitioningAnimation.swift in Sources */,
C6456F0627FF291D00A517D5 /* GradientView.swift in Sources */,
C63414DA2A7D335100C80B77 /* GlobalRR.swift in Sources */,
C62900EE2BAAC5C0008B35A2 /* BalanceTokenIconsView.swift in Sources */,
29BECD0E2979BD7B00662FC1 /* CloudStorage.swift in Sources */,
C6D0F438283F7DFF00444921 /* MintDomainsConfigurationSelectionCell.swift in Sources */,
3004E32726D528D300B9CB6A /* LegacyUnitaryWallet.swift in Sources */,
Expand All @@ -8709,6 +8741,7 @@
C60EE80F2ACD203000D699C7 /* NetworkService+MessagingApi.swift in Sources */,
C6D9E28928533783002CDAC2 /* UDDomainSharingCardView.swift in Sources */,
C673BA2E2A81EA2F001FD763 /* XMTPServiceSharedHelper.swift in Sources */,
C62900F52BAAC83A008B35A2 /* SelectTokenAssetAmountToSendView.swift in Sources */,
C69698982ACBCDDB0000738C /* PushWebSocketsService.swift in Sources */,
C609821C2823D36100546392 /* PullUpCollectionViewCell.swift in Sources */,
C6C9958E289D313D00367362 /* CNavigationTransitioningContext.swift in Sources */,
Expand Down Expand Up @@ -8754,6 +8787,7 @@
C6ECBF7528D2C6D300E94309 /* BaseMintingTransactionInProgressViewPresenter.swift in Sources */,
C638680B2858DA0F000F98C4 /* KeepingAnimationImageView.swift in Sources */,
C6D6E527281932FF008C66BB /* BaseViewControllerProtocol.swift in Sources */,
C62900FB2BAACCD2008B35A2 /* UDNumberPadView.swift in Sources */,
307B1CEA2602775D007B14C3 /* UDWallet.swift in Sources */,
C6B6B028296D2CEA00D4E30F /* MintingDomainWithDisplayInfo.swift in Sources */,
C60982562823FDE100546392 /* CreateLocalWalletRecoveryPhrasePresenter.swift in Sources */,
Expand Down Expand Up @@ -8804,6 +8838,7 @@
C6ECBF7A28D2C86F00E94309 /* ReverseResolutionTransactionInProgressViewPresenter.swift in Sources */,
C645131128095BA400413C51 /* ExistingUsersTutorialViewController.swift in Sources */,
C6D6E4F72817E045008C66BB /* OnboardingConfirmWordsPresenter.swift in Sources */,
C62900F82BAAC922008B35A2 /* UDNumberButtonView.swift in Sources */,
C6B65F6A2B550E72006D1812 /* NFTModel.swift in Sources */,
C6526DD429D2DE0700D6F2EB /* LoadingParkedDomainsOnboardingViewPresenter.swift in Sources */,
C63095D22B0DA5DE00205054 /* DomainToPurchase.swift in Sources */,
Expand Down Expand Up @@ -9558,6 +9593,7 @@
30972CC4258A62A700D7E229 /* LocalStorage.swift in Sources */,
C69F997C2A9F2206004B1958 /* PublicProfileSocialsListView.swift in Sources */,
C674598F280E9CA20074CBE5 /* WebViewController.swift in Sources */,
C62901002BAAD3C3008B35A2 /* NumberPadInputInterpreter.swift in Sources */,
C6D0F442283F870F00444921 /* MintDomainsConfigurationListHeaderView.swift in Sources */,
C64939F22B6357A600457363 /* HomeTabRouter.swift in Sources */,
C67213E92BAA99080075B9C7 /* SelectCryptoAssetToSendView.swift in Sources */,
Expand Down Expand Up @@ -9715,6 +9751,7 @@
C6DF9871290F83020098733A /* ResolutionInitTests.swift in Sources */,
29EDB623290A94E700A0BD08 /* ProfilesTests.swift in Sources */,
C6D011CE2B99A3C90008BF40 /* TestableUserProfileService.swift in Sources */,
C62900FE2BAAD126008B35A2 /* NumberPadInputInterpreterTests.swift in Sources */,
C680178E2886E96400524712 /* XCTest.swift in Sources */,
C6D011D02B99A7740008BF40 /* FailableService.swift in Sources */,
C6DF9879290F832A0098733A /* WebsiteURLValidatorTests.swift in Sources */,
Expand Down Expand Up @@ -9922,6 +9959,7 @@
C6C8F8CD2B21832F00A9834D /* BaseMintingTransactionInProgressViewPresenter.swift in Sources */,
C6C8F8592B217F8200A9834D /* PreviewiCloudPrivateKeyStorage.swift in Sources */,
C6D6468B2B1ED12D00D724AC /* DomainProfileCryptoSection.swift in Sources */,
C62900F62BAAC83A008B35A2 /* SelectTokenAssetAmountToSendView.swift in Sources */,
C64F8E022B60F2590075D37F /* ViewPullUpConfigurationType.swift in Sources */,
C6D646EC2B1ED55F00D724AC /* NFCService+Entities.swift in Sources */,
C6D647252B1ED91F00D724AC /* PullUpViewService+Messaging.swift in Sources */,
Expand Down Expand Up @@ -10292,6 +10330,7 @@
C650E2942B9E97F2002C120A /* UDButtonStyle+Large.swift in Sources */,
C618084E2B19B9FD0032E543 /* PreviewFirebasePurchaseDomainsService.swift in Sources */,
C6B65F952B5665F0006D1812 /* HomeTabView.swift in Sources */,
C62900EF2BAAC5C0008B35A2 /* BalanceTokenIconsView.swift in Sources */,
C6D647212B1ED91F00D724AC /* PullUpViewService.swift in Sources */,
C6C8F8A12B2182AE00A9834D /* WalletDetailsViewController.swift in Sources */,
C6D8FF1F2B82EB740094A21E /* TextMessageRowView.swift in Sources */,
Expand Down Expand Up @@ -10336,6 +10375,7 @@
C6C8F83E2B217E9600A9834D /* RecoveryPhraseViewController.swift in Sources */,
C6C8F8742B21822700A9834D /* TutorialStepViewController.swift in Sources */,
C6C8F8BF2B2182E400A9834D /* ChangeWalletsReverseResolutionDomainViewPresenter.swift in Sources */,
C62900FC2BAACCD2008B35A2 /* UDNumberPadView.swift in Sources */,
C6C8F82A2B217D7C00A9834D /* WCRegistryWalletProxy.swift in Sources */,
C6D647042B1ED7C300D724AC /* MessagingGroupChatDetails.swift in Sources */,
C61808232B19AB250032E543 /* PurchaseDomainsPreferencesStorage.swift in Sources */,
Expand Down Expand Up @@ -10555,6 +10595,7 @@
C60C59B62B47FC0900A2522C /* LoginProvider.swift in Sources */,
C6C8F9222B2183B700A9834D /* EnterPasscodeViewController.swift in Sources */,
C6D646352B1DC44400D724AC /* PrimaryDangerButton.swift in Sources */,
C62900F92BAAC922008B35A2 /* UDNumberButtonView.swift in Sources */,
C6D646052B1DC01700D724AC /* DashesProgressView.swift in Sources */,
C6C8F85B2B217FB500A9834D /* WalletBackUpPassword.swift in Sources */,
C6D647812B1EE1FC00D724AC /* UDCheckBox.swift in Sources */,
Expand Down Expand Up @@ -10677,6 +10718,7 @@
C6B65FAE2B57A5BB006D1812 /* DismissIndicatorView.swift in Sources */,
C6D646AA2B1ED15F00D724AC /* DomainProfileViewPresenter.swift in Sources */,
C6D646592B1ED10D00D724AC /* DomainProfileMetadataCell.swift in Sources */,
C62901012BAAD3C3008B35A2 /* NumberPadInputInterpreter.swift in Sources */,
C61807B22B199DD70032E543 /* UIView.swift in Sources */,
C6203A552B88356E000A1A8E /* HomeExploreNavigationDestination.swift in Sources */,
C61807E32B19A57D0032E543 /* DomainsSortOrderStorage.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// NumberPadInputInterpreter.swift
// domains-manager-ios
//
// Created by Oleg Kuplin on 20.03.2024.
//

import Foundation

struct NumberPadInputInterpreter {
private var input: String = ""

mutating func addInput(_ inputType: UDNumberButtonView.InputType) {
switch inputType {
case .number(let num):
if num == 0,
input == "0" {
return
}
input.append(String(num))
case .dot:
if !isContainsDot() {
input += .dotSeparator
}
case .erase:
if !input.isEmpty {
input.removeLast()
}
}
}

private func isContainsDot() -> Bool {
input.contains(.dotSeparator)
}

func getInterpretedNumber() -> Double {
if input.last == .dotSeparator {
return Double(input.dropLast()) ?? 0
}
return Double(input) ?? 0
}

func getInput() -> String {
if input.isEmpty {
return "0"
} else if input.first == String.dotSeparator.first {
return "0" + input
}
return input
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,9 @@ extension String {
static let selectPullUpBuyDomainsSubtitle = "SELECT_PULL_UP_BUY_DOMAINS_SUBTITLE"
static let selectPullUpBuyTokensSubtitle = "SELECT_PULL_UP_BUY_TOKENS_SUBTITLE"

static let review = "REVIEW"
static let usingMax = "USING_MAX"
static let useMax = "USE_MAX"
}

enum BlockChainIcons: String {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//
// BalanceTokenIconsView.swift
// domains-manager-ios
//
// Created by Oleg Kuplin on 20.03.2024.
//

import SwiftUI

struct BalanceTokenIconsView: View {

let token: BalanceTokenUIDescription

@State private var icon: UIImage?
@State private var parentIcon: UIImage?

var body: some View {
ZStack(alignment: .bottomTrailing) {
Image(uiImage: icon ?? .init())
.resizable()
.squareFrame(40)
.background(Color.backgroundSubtle)
.skeletonable()
.clipShape(Circle())

if token.parentSymbol != nil {
Image(uiImage: parentIcon ?? .init())
.resizable()
.squareFrame(20)
.background(Color.backgroundDefault)
.skeletonable()
.clipShape(Circle())
.overlay {
Circle()
.stroke(lineWidth: 2)
.foregroundStyle(Color.backgroundDefault)
}
.offset(x: 4, y: 4)
}
}
.onChange(of: token, perform: { newValue in
loadIconFor(token: newValue)
})
.onAppear(perform: onAppear)
}
}

// MARK: - Private methods
private extension BalanceTokenIconsView {
func onAppear() {
loadIconFor(token: token)
}

func loadIconFor(token: BalanceTokenUIDescription) {
guard !token.isSkeleton else {
icon = nil
parentIcon = nil
return }

token.loadTokenIcon { image in
self.icon = image
}
token.loadParentIcon { image in
self.parentIcon = image
}
}
}

#Preview {
BalanceTokenIconsView(token: MockEntitiesFabric.Tokens.mockUIToken())
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,63 +11,16 @@ struct SelectCryptoAssetToSendTokenView: View {

let token: BalanceTokenUIDescription

@State private var icon: UIImage?
@State private var parentIcon: UIImage?

var body: some View {
HStack(spacing: 16) {
iconView()
BalanceTokenIconsView(token: token)
tokenInfoView()
}
.onAppear(perform: onAppear)
}
}

// MARK: - Private methods
private extension SelectCryptoAssetToSendTokenView {
func onAppear() {
loadIconFor(token: token)
}

func loadIconFor(token: BalanceTokenUIDescription) {
token.loadTokenIcon { image in
self.icon = image
}
token.loadParentIcon { image in
self.parentIcon = image
}
}
}

// MARK: - Private methods
private extension SelectCryptoAssetToSendTokenView {
@ViewBuilder
func iconView() -> some View {
ZStack(alignment: .bottomTrailing) {
Image(uiImage: icon ?? .init())
.resizable()
.squareFrame(40)
.background(Color.backgroundSubtle)
.skeletonable()
.clipShape(Circle())

if token.parentSymbol != nil {
Image(uiImage: parentIcon ?? .init())
.resizable()
.squareFrame(20)
.background(Color.backgroundDefault)
.skeletonable()
.clipShape(Circle())
.overlay {
Circle()
.stroke(lineWidth: 2)
.foregroundStyle(Color.backgroundDefault)
}
.offset(x: 4, y: 4)
}
}
}

@ViewBuilder
func tokenInfoView() -> some View {
HStack(spacing: 0) {
Expand Down
Loading

0 comments on commit 071002f

Please sign in to comment.