From 2fcd3fbc9ff593e5a2b7e66da896f17eff1b22f0 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Wed, 16 Oct 2024 17:28:41 +0200 Subject: [PATCH 01/63] WIP --- RadixWallet.xcodeproj/project.pbxproj | 28 +++++++++++++++++++ .../PreAuthorizationReview+View.swift | 24 ++++++++++++++++ .../PreAuthorizationReview.swift | 25 +++++++++++++++++ .../ReviewCommon/InteractionReview.swift | 24 ++++++++++++++++ 4 files changed, 101 insertions(+) create mode 100644 RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift create mode 100644 RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift create mode 100644 RadixWallet/Features/PreAuthorizationReview/ReviewCommon/InteractionReview.swift diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index 58fab228b5..5dcf205d02 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -734,6 +734,9 @@ 5B45E2FF2BC59780007C4C84 /* SignWithFactorSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B45E2FD2BC59780007C4C84 /* SignWithFactorSource.swift */; }; 5B45E3012BC5A491007C4C84 /* FactorSourceAccess+ViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B45E3002BC5A491007C4C84 /* FactorSourceAccess+ViewState.swift */; }; 5B4712CC2C526146003B4712 /* HeaderButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4712CB2C526146003B4712 /* HeaderButtonStyle.swift */; }; + 5B4A1ABF2CC00FB800679EE6 /* PreAuthorizationReview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */; }; + 5B4A1AC02CC00FB800679EE6 /* PreAuthorizationReview+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */; }; + 5B4A1AC42CC0125700679EE6 /* InteractionReview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */; }; 5B4E1D132CB421EB002FAC2E /* DepositStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4E1D122CB421E3002FAC2E /* DepositStatus.swift */; }; 5B526ADB2C876E7C00AF8B72 /* AccountLockerClaimDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B526ADA2C876E7C00AF8B72 /* AccountLockerClaimDetails.swift */; }; 5B526AEC2C89C3C200AF8B72 /* ResourcesVisibilityClient+Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B526AE82C89C3C200AF8B72 /* ResourcesVisibilityClient+Interface.swift */; }; @@ -1947,6 +1950,9 @@ 5B45E2FD2BC59780007C4C84 /* SignWithFactorSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignWithFactorSource.swift; sourceTree = ""; }; 5B45E3002BC5A491007C4C84 /* FactorSourceAccess+ViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FactorSourceAccess+ViewState.swift"; sourceTree = ""; }; 5B4712CB2C526146003B4712 /* HeaderButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderButtonStyle.swift; sourceTree = ""; }; + 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreAuthorizationReview.swift; sourceTree = ""; }; + 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationReview+View.swift"; sourceTree = ""; }; + 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractionReview.swift; sourceTree = ""; }; 5B4E1D122CB421E3002FAC2E /* DepositStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepositStatus.swift; sourceTree = ""; }; 5B526ADA2C876E7C00AF8B72 /* AccountLockerClaimDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountLockerClaimDetails.swift; sourceTree = ""; }; 5B526AE82C89C3C200AF8B72 /* ResourcesVisibilityClient+Interface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ResourcesVisibilityClient+Interface.swift"; sourceTree = ""; }; @@ -2687,6 +2693,7 @@ 48CFBCBF2ADC10D800E77A5C /* P2PLinksFeature */, 48CFBCC62ADC10D800E77A5C /* AppFeature */, 48CFBCD02ADC10D800E77A5C /* TransactionReviewFeature */, + 5B4A1ABC2CC00F7F00679EE6 /* PreAuthorizationReview */, 48CFBCF92ADC10D800E77A5C /* DappsAndPersonas */, 48CFBD0E2ADC10D800E77A5C /* HomeFeature */, 48CFBD192ADC10D800E77A5C /* DerivePublicKeys */, @@ -5517,6 +5524,24 @@ path = FactorSourceAccess; sourceTree = ""; }; + 5B4A1ABC2CC00F7F00679EE6 /* PreAuthorizationReview */ = { + isa = PBXGroup; + children = ( + 5B4A1AC22CC0120600679EE6 /* ReviewCommon */, + 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */, + 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */, + ); + path = PreAuthorizationReview; + sourceTree = ""; + }; + 5B4A1AC22CC0120600679EE6 /* ReviewCommon */ = { + isa = PBXGroup; + children = ( + 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */, + ); + path = ReviewCommon; + sourceTree = ""; + }; 5B526AEB2C89C3C200AF8B72 /* ResourcesVisibilityClient */ = { isa = PBXGroup; children = ( @@ -7240,6 +7265,7 @@ 48CFC27A2ADC10D900E77A5C /* App+View.swift in Sources */, A40815E72C7E0D08005E65B9 /* ProgrammaticScryptoSborValueU128.swift in Sources */, E7AE2D0E2C07359500830BAA /* FullScreenOverlayCoordinator+Reducer.swift in Sources */, + 5B4A1AC42CC0125700679EE6 /* InteractionReview.swift in Sources */, 48CFC3ED2ADC10D900E77A5C /* DataChannelMessage+Codable.swift in Sources */, A408163B2C7E0D08005E65B9 /* TransactionAccountDepositPreValidationAuthorizedDepositorBadge.swift in Sources */, 48CFC5DA2ADC10DA00E77A5C /* PresentationDetentIntrinsicHeight.swift in Sources */, @@ -7761,6 +7787,8 @@ A40815822C7E0D08005E65B9 /* InvalidEntityError.swift in Sources */, 48CFC5DE2ADC10DA00E77A5C /* OnFirstTaskViewModifier.swift in Sources */, 489122782B186F61005F2EEE /* AlternativeRectangularButtonStyle.swift in Sources */, + 5B4A1ABF2CC00FB800679EE6 /* PreAuthorizationReview.swift in Sources */, + 5B4A1AC02CC00FB800679EE6 /* PreAuthorizationReview+View.swift in Sources */, 48CFC3652ADC10D900E77A5C /* NonFungibleTokenDetails+View.swift in Sources */, 48CFC5C42ADC10DA00E77A5C /* Separator.swift in Sources */, 48CFC46C2ADC10DA00E77A5C /* ParseOlympiaPayloads.swift in Sources */, diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift new file mode 100644 index 0000000000..5927b88f39 --- /dev/null +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -0,0 +1,24 @@ +import SwiftUI + +// MARK: - PreAuthorizationReview.View +extension PreAuthorizationReview { + struct View: SwiftUI.View { + let store: StoreOf + + var body: some SwiftUI.View { + WithPerceptionTracking { + // TODO: implement + Text("Implement: PreAuthorizationReview") + .background(Color.yellow) + .foregroundColor(.red) + .onAppear { store.send(.view(.appeared)) } + } + } + + private var content: some SwiftUI.View { + ScrollView(showsIndicators: false) { + VStack(spacing: .zero) {} + } + } + } +} diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift new file mode 100644 index 0000000000..59cb470d78 --- /dev/null +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -0,0 +1,25 @@ +// MARK: - PreAuthorizationReview +@Reducer +struct PreAuthorizationReview: Sendable, FeatureReducer { + @ObservableState + struct State: Sendable, Hashable { + init() {} + } + + typealias Action = FeatureAction + + enum ViewAction: Sendable, Equatable { + case appeared + } + + var body: some ReducerOf { + Reduce(core) + } + + func reduce(into state: inout State, viewAction: ViewAction) -> Effect { + switch viewAction { + case .appeared: + .none + } + } +} diff --git a/RadixWallet/Features/PreAuthorizationReview/ReviewCommon/InteractionReview.swift b/RadixWallet/Features/PreAuthorizationReview/ReviewCommon/InteractionReview.swift new file mode 100644 index 0000000000..23f8aadd80 --- /dev/null +++ b/RadixWallet/Features/PreAuthorizationReview/ReviewCommon/InteractionReview.swift @@ -0,0 +1,24 @@ +import SwiftUI + +// MARK: - InteractionReview +// Namespace to group every subview common to TransactionReview and PreAuthorizationReview +enum InteractionReview {} + +// MARK: InteractionReview.Kind +extension InteractionReview { + enum Kind: Sendable, Hashable { + case transaction + case preAuthorization + } +} + +// MARK: InteractionReview.HeaderView +extension InteractionReview { + struct HeaderView: View { + let kind: Kind + + var body: some View { + EmptyView() + } + } +} From ab48dbaad1e1610820b9da55a231500970ee6b65 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Wed, 16 Oct 2024 18:34:22 +0200 Subject: [PATCH 02/63] wip --- RadixWallet.xcodeproj/project.pbxproj | 10 ++- .../InteractionReview/HeaderView.swift | 55 +++++++++++++++ .../InteractionReview/InteractionReview.swift | 13 ++++ .../PreAuthorizationReview+View.swift | 68 +++++++++++++++++-- .../PreAuthorizationReview.swift | 1 + .../ReviewCommon/InteractionReview.swift | 24 ------- .../TransactionReview+View.swift | 36 +++------- 7 files changed, 148 insertions(+), 59 deletions(-) create mode 100644 RadixWallet/Features/PreAuthorizationReview/InteractionReview/HeaderView.swift create mode 100644 RadixWallet/Features/PreAuthorizationReview/InteractionReview/InteractionReview.swift delete mode 100644 RadixWallet/Features/PreAuthorizationReview/ReviewCommon/InteractionReview.swift diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index 5dcf205d02..e21fbeb61c 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -737,6 +737,7 @@ 5B4A1ABF2CC00FB800679EE6 /* PreAuthorizationReview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */; }; 5B4A1AC02CC00FB800679EE6 /* PreAuthorizationReview+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */; }; 5B4A1AC42CC0125700679EE6 /* InteractionReview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */; }; + 5B4A1AC62CC0151300679EE6 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */; }; 5B4E1D132CB421EB002FAC2E /* DepositStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4E1D122CB421E3002FAC2E /* DepositStatus.swift */; }; 5B526ADB2C876E7C00AF8B72 /* AccountLockerClaimDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B526ADA2C876E7C00AF8B72 /* AccountLockerClaimDetails.swift */; }; 5B526AEC2C89C3C200AF8B72 /* ResourcesVisibilityClient+Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B526AE82C89C3C200AF8B72 /* ResourcesVisibilityClient+Interface.swift */; }; @@ -1953,6 +1954,7 @@ 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreAuthorizationReview.swift; sourceTree = ""; }; 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationReview+View.swift"; sourceTree = ""; }; 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractionReview.swift; sourceTree = ""; }; + 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = ""; }; 5B4E1D122CB421E3002FAC2E /* DepositStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepositStatus.swift; sourceTree = ""; }; 5B526ADA2C876E7C00AF8B72 /* AccountLockerClaimDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountLockerClaimDetails.swift; sourceTree = ""; }; 5B526AE82C89C3C200AF8B72 /* ResourcesVisibilityClient+Interface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ResourcesVisibilityClient+Interface.swift"; sourceTree = ""; }; @@ -5527,19 +5529,20 @@ 5B4A1ABC2CC00F7F00679EE6 /* PreAuthorizationReview */ = { isa = PBXGroup; children = ( - 5B4A1AC22CC0120600679EE6 /* ReviewCommon */, + 5B4A1AC22CC0120600679EE6 /* InteractionReview */, 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */, 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */, ); path = PreAuthorizationReview; sourceTree = ""; }; - 5B4A1AC22CC0120600679EE6 /* ReviewCommon */ = { + 5B4A1AC22CC0120600679EE6 /* InteractionReview */ = { isa = PBXGroup; children = ( 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */, + 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */, ); - path = ReviewCommon; + path = InteractionReview; sourceTree = ""; }; 5B526AEB2C89C3C200AF8B72 /* ResourcesVisibilityClient */ = { @@ -7599,6 +7602,7 @@ A4CFB55F2BAA821E00778BDD /* HScrollBar.swift in Sources */, 48CFC44D2ADC10DA00E77A5C /* MnemonicClient+Live.swift in Sources */, 48CFC57E2ADC10DA00E77A5C /* ValidatorState.swift in Sources */, + 5B4A1AC62CC0151300679EE6 /* HeaderView.swift in Sources */, A40815852C7E0D08005E65B9 /* LedgerState.swift in Sources */, 48CFC3882ADC10D900E77A5C /* DisplayEntitiesControlledByMnemonic+View.swift in Sources */, 48CFC57A2ADC10DA00E77A5C /* ResourcePoolState.swift in Sources */, diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReview/HeaderView.swift b/RadixWallet/Features/PreAuthorizationReview/InteractionReview/HeaderView.swift new file mode 100644 index 0000000000..ec5d2ec310 --- /dev/null +++ b/RadixWallet/Features/PreAuthorizationReview/InteractionReview/HeaderView.swift @@ -0,0 +1,55 @@ +import SwiftUI + +// MARK: InteractionReview.HeaderView +extension InteractionReview { + struct HeaderView: View { + let kind: Kind + let name: String? + let thumbnail: URL? + + var body: some View { + VStack(alignment: .leading, spacing: .small2) { + Text(title) + .textStyle(.sheetTitle) + .lineLimit(2) + .multilineTextAlignment(.leading) + .foregroundColor(.app.gray1) + + if showBottom { + HStack(spacing: .small2) { + if let thumbnail { + Thumbnail(.dapp, url: thumbnail, size: .smallest) + } + Text(subtitle) + .textStyle(.body2HighImportance) + .foregroundColor(.app.gray1) + } + } + } + .frame(maxWidth: .infinity, alignment: .leading) + } + + private var title: String { + switch kind { + case .transaction: + L10n.TransactionReview.title + case .preAuthorization: + "Review Your Pre-Authorization" + } + } + + private var subtitle: String? { + guard let name else { return nil } + switch kind { + case .transaction: + return L10n.TransactionReview.proposingDappSubtitle(name) + case .preAuthorization: + return "Proposed by \(name)" + } + } + + private var showBottom: Bool { + thumbnail != nil || name != nil + } + } +} diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReview/InteractionReview.swift b/RadixWallet/Features/PreAuthorizationReview/InteractionReview/InteractionReview.swift new file mode 100644 index 0000000000..cc9ee8d512 --- /dev/null +++ b/RadixWallet/Features/PreAuthorizationReview/InteractionReview/InteractionReview.swift @@ -0,0 +1,13 @@ +import SwiftUI + +// MARK: - InteractionReview +/// Namespace to group every subview common to `TransactionReview` and `PreAuthorizationReview` +enum InteractionReview {} + +// MARK: InteractionReview.Kind +extension InteractionReview { + enum Kind: Sendable, Hashable { + case transaction + case preAuthorization + } +} diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index 5927b88f39..52902f9f5b 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -5,20 +5,76 @@ extension PreAuthorizationReview { struct View: SwiftUI.View { let store: StoreOf + @SwiftUI.State private var showNavigationTitle = false + + private let coordSpace: String = "PreAuthorizationReviewCoordSpace" + private let navTitleID: String = "PreAuthorizationReview.title" + private let showTitleHysteresis: CGFloat = .small3 + var body: some SwiftUI.View { WithPerceptionTracking { - // TODO: implement - Text("Implement: PreAuthorizationReview") - .background(Color.yellow) - .foregroundColor(.red) - .onAppear { store.send(.view(.appeared)) } + content + .background(.app.white) + .toolbar { + ToolbarItem(placement: .principal) { + if showNavigationTitle { + navigationTitle + } + } + } + } + } + + private var navigationTitle: some SwiftUI.View { + VStack(spacing: .zero) { + Text("Review your Pre-Authorization") + .textStyle(.body2Header) + .foregroundColor(.app.gray1) + + if let name = store.dappName { + Text("Proposed by \(name)") + .textStyle(.body2Regular) + .foregroundColor(.app.gray2) + } } } private var content: some SwiftUI.View { ScrollView(showsIndicators: false) { - VStack(spacing: .zero) {} + VStack(spacing: .zero) { + header + + ForEach(0 ..< 30) { index in + Text("Row \(index)") + .padding() + } + + Spacer() + } + } + .coordinateSpace(name: coordSpace) + .onPreferenceChange(PositionsPreferenceKey.self) { positions in + guard let offset = positions[navTitleID]?.maxY else { + showNavigationTitle = true + return + } + if showNavigationTitle, offset > showTitleHysteresis { + showNavigationTitle = false + } else if !showNavigationTitle, offset < 0 { + showNavigationTitle = true + } } } + + private var header: some SwiftUI.View { + InteractionReview.HeaderView( + kind: .preAuthorization, + name: store.dappName, + thumbnail: nil + ) + .measurePosition(navTitleID, coordSpace: coordSpace) + .padding(.horizontal, .medium3) + .padding(.bottom, .medium3) + } } } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 59cb470d78..43808b4e4d 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -3,6 +3,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { @ObservableState struct State: Sendable, Hashable { + var dappName: String? = "Collabo.Fi" init() {} } diff --git a/RadixWallet/Features/PreAuthorizationReview/ReviewCommon/InteractionReview.swift b/RadixWallet/Features/PreAuthorizationReview/ReviewCommon/InteractionReview.swift deleted file mode 100644 index 23f8aadd80..0000000000 --- a/RadixWallet/Features/PreAuthorizationReview/ReviewCommon/InteractionReview.swift +++ /dev/null @@ -1,24 +0,0 @@ -import SwiftUI - -// MARK: - InteractionReview -// Namespace to group every subview common to TransactionReview and PreAuthorizationReview -enum InteractionReview {} - -// MARK: InteractionReview.Kind -extension InteractionReview { - enum Kind: Sendable, Hashable { - case transaction - case preAuthorization - } -} - -// MARK: InteractionReview.HeaderView -extension InteractionReview { - struct HeaderView: View { - let kind: Kind - - var body: some View { - EmptyView() - } - } -} diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index 85f9aad335..27bfe58e71 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -150,12 +150,6 @@ extension TransactionReview { ScrollView(showsIndicators: false) { VStack(spacing: 0) { header(viewStore.proposingDappMetadata) - .measurePosition(navTitleID, coordSpace: coordSpace) - .padding(.horizontal, .medium3) - .padding(.bottom, .medium3) - .background { - JaggedEdge(shadowColor: shadowColor, isTopEdge: true) - } if let rawTransaction = viewStore.rawTransaction { RawTransactionView(transaction: rawTransaction) { @@ -252,27 +246,17 @@ extension TransactionReview { } private func header(_ proposingDappMetadata: DappMetadata.Ledger?) -> some SwiftUI.View { - VStack(alignment: .leading, spacing: .small2) { - Text(L10n.TransactionReview.title) - .textStyle(.sheetTitle) - .lineLimit(2) - .multilineTextAlignment(.leading) - .foregroundColor(.app.gray1) - - if proposingDappMetadata?.thumbnail != nil || proposingDappMetadata?.name != nil { - HStack(spacing: .small2) { - if let thumbnail = proposingDappMetadata?.thumbnail { - Thumbnail(.dapp, url: thumbnail, size: .smallest) - } - if let name = proposingDappMetadata?.name { - Text(L10n.TransactionReview.proposingDappSubtitle(name.rawValue)) - .textStyle(.body2HighImportance) - .foregroundColor(.app.gray1) - } - } - } + InteractionReview.HeaderView( + kind: .transaction, + name: proposingDappMetadata?.name?.rawValue, + thumbnail: proposingDappMetadata?.thumbnail + ) + .measurePosition(navTitleID, coordSpace: coordSpace) + .padding(.horizontal, .medium3) + .padding(.bottom, .medium3) + .background { + JaggedEdge(shadowColor: shadowColor, isTopEdge: true) } - .frame(maxWidth: .infinity, alignment: .leading) } @ViewBuilder From 4811e0c862faf32fc5580a9a4c308751b255d6b4 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Thu, 17 Oct 2024 13:32:14 +0200 Subject: [PATCH 03/63] WIP --- RadixWallet.xcodeproj/project.pbxproj | 14 +++- .../InteractionReview/InteractionReview.swift | 13 ---- .../InteractionReviewCommon/DisplayMode.swift | 13 ++++ .../HeaderView.swift | 3 +- .../InteractionReview.swift | 13 ++++ .../RawTransactionView.swift | 64 +++++++++++++++++++ .../PreAuthorizationReview+View.swift | 17 +++-- .../PreAuthorizationReview.swift | 3 + .../TransactionReview+View.swift | 38 +---------- .../TransactionReview.swift | 17 ++--- 10 files changed, 124 insertions(+), 71 deletions(-) delete mode 100644 RadixWallet/Features/PreAuthorizationReview/InteractionReview/InteractionReview.swift create mode 100644 RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/DisplayMode.swift rename RadixWallet/Features/PreAuthorizationReview/{InteractionReview => InteractionReviewCommon}/HeaderView.swift (94%) create mode 100644 RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/InteractionReview.swift create mode 100644 RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/RawTransactionView.swift diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index e21fbeb61c..a027b2fab5 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -710,6 +710,8 @@ 48FFFB082ADC6FD300B2B213 /* SwiftUINavigationCore in Frameworks */ = {isa = PBXBuildFile; productRef = 48FFFB072ADC6FD300B2B213 /* SwiftUINavigationCore */; }; 48FFFB0A2ADC721800B2B213 /* Atomics in Frameworks */ = {isa = PBXBuildFile; productRef = 48FFFB092ADC721800B2B213 /* Atomics */; }; 48FFFB0D2ADC744700B2B213 /* TextBuilder in Frameworks */ = {isa = PBXBuildFile; productRef = 48FFFB0C2ADC744700B2B213 /* TextBuilder */; }; + 5B03E3CF2CC1223000E10A64 /* DisplayMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B03E3CE2CC1222D00E10A64 /* DisplayMode.swift */; }; + 5B03E3D12CC127B100E10A64 /* RawTransactionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */; }; 5B135B392C7636DA004AAD2E /* HiddenEntities+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B135B382C7636DA004AAD2E /* HiddenEntities+View.swift */; }; 5B135B3B2C7636FD004AAD2E /* HiddenEntities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B135B3A2C7636FD004AAD2E /* HiddenEntities.swift */; }; 5B1C4FD52BBB0B0C00B9436F /* AppsFlyerLib-Strict in Frameworks */ = {isa = PBXBuildFile; productRef = 5B1C4FD42BBB0B0C00B9436F /* AppsFlyerLib-Strict */; }; @@ -1928,6 +1930,8 @@ 48DD0FF62BCBCBB900C54C43 /* Stage1MigrateToSargon+AssetException.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Stage1MigrateToSargon+AssetException.swift"; sourceTree = ""; }; 48FF43142AE43C7C00C568B9 /* TimeLimit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeLimit.swift; sourceTree = ""; }; 48FFFAF12ADC23AC00B2B213 /* Exports.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Exports.swift; sourceTree = ""; }; + 5B03E3CE2CC1222D00E10A64 /* DisplayMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayMode.swift; sourceTree = ""; }; + 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawTransactionView.swift; sourceTree = ""; }; 5B135B382C7636DA004AAD2E /* HiddenEntities+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HiddenEntities+View.swift"; sourceTree = ""; }; 5B135B3A2C7636FD004AAD2E /* HiddenEntities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HiddenEntities.swift; sourceTree = ""; }; 5B1C4FD72BBB0C1E00B9436F /* AppsFlyerClient+Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppsFlyerClient+Interface.swift"; sourceTree = ""; }; @@ -5529,20 +5533,22 @@ 5B4A1ABC2CC00F7F00679EE6 /* PreAuthorizationReview */ = { isa = PBXGroup; children = ( - 5B4A1AC22CC0120600679EE6 /* InteractionReview */, + 5B4A1AC22CC0120600679EE6 /* InteractionReviewCommon */, 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */, 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */, ); path = PreAuthorizationReview; sourceTree = ""; }; - 5B4A1AC22CC0120600679EE6 /* InteractionReview */ = { + 5B4A1AC22CC0120600679EE6 /* InteractionReviewCommon */ = { isa = PBXGroup; children = ( + 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */, 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */, + 5B03E3CE2CC1222D00E10A64 /* DisplayMode.swift */, 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */, ); - path = InteractionReview; + path = InteractionReviewCommon; sourceTree = ""; }; 5B526AEB2C89C3C200AF8B72 /* ResourcesVisibilityClient */ = { @@ -7975,6 +7981,7 @@ A408158E2C7E0D08005E65B9 /* MetadataGlobalAddressValue.swift in Sources */, A40815E52C7E0D08005E65B9 /* ProgrammaticScryptoSborValueU32.swift in Sources */, A40815B82C7E0D08005E65B9 /* NativeResourceSecp256k1SignatureResourceValue.swift in Sources */, + 5B03E3CF2CC1223000E10A64 /* DisplayMode.swift in Sources */, A408165A2C7E0D08005E65B9 /* ValidatorCollection.swift in Sources */, E7A5AC9A2C09F453006CB6EC /* ResetWalletClient+Test.swift in Sources */, A462B5BB2B90C5E800C26D20 /* ResourceBalance+Helpers.swift in Sources */, @@ -7988,6 +7995,7 @@ A40815FA2C7E0D08005E65B9 /* ScryptoSborValue.swift in Sources */, 48CFC5F02ADC10DA00E77A5C /* UserDefaultsClient+AccountRecovery.swift in Sources */, A408161A2C7E0D08005E65B9 /* StateEntityNonFungibleResourceVaultsPageRequest.swift in Sources */, + 5B03E3D12CC127B100E10A64 /* RawTransactionView.swift in Sources */, 48CFC3562ADC10D900E77A5C /* ImportOlympiaLedgerAccountsAndFactorSources.swift in Sources */, 48CFC5782ADC10DA00E77A5C /* GatewayError.swift in Sources */, 48CFC5E62ADC10DA00E77A5C /* SwiftUINavigation+Extra.swift in Sources */, diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReview/InteractionReview.swift b/RadixWallet/Features/PreAuthorizationReview/InteractionReview/InteractionReview.swift deleted file mode 100644 index cc9ee8d512..0000000000 --- a/RadixWallet/Features/PreAuthorizationReview/InteractionReview/InteractionReview.swift +++ /dev/null @@ -1,13 +0,0 @@ -import SwiftUI - -// MARK: - InteractionReview -/// Namespace to group every subview common to `TransactionReview` and `PreAuthorizationReview` -enum InteractionReview {} - -// MARK: InteractionReview.Kind -extension InteractionReview { - enum Kind: Sendable, Hashable { - case transaction - case preAuthorization - } -} diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/DisplayMode.swift b/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/DisplayMode.swift new file mode 100644 index 0000000000..aa3777815d --- /dev/null +++ b/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/DisplayMode.swift @@ -0,0 +1,13 @@ +import Foundation + +extension InteractionReviewCommon { + enum DisplayMode: Sendable, Hashable { + case detailed + case raw(String) + + var rawTransaction: String? { + guard case let .raw(transaction) = self else { return nil } + return transaction + } + } +} diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReview/HeaderView.swift b/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/HeaderView.swift similarity index 94% rename from RadixWallet/Features/PreAuthorizationReview/InteractionReview/HeaderView.swift rename to RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/HeaderView.swift index ec5d2ec310..832386b96f 100644 --- a/RadixWallet/Features/PreAuthorizationReview/InteractionReview/HeaderView.swift +++ b/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/HeaderView.swift @@ -1,7 +1,6 @@ import SwiftUI -// MARK: InteractionReview.HeaderView -extension InteractionReview { +extension InteractionReviewCommon { struct HeaderView: View { let kind: Kind let name: String? diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/InteractionReview.swift b/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/InteractionReview.swift new file mode 100644 index 0000000000..296bf3deee --- /dev/null +++ b/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/InteractionReview.swift @@ -0,0 +1,13 @@ +import SwiftUI + +// MARK: - InteractionReviewCommon +/// Namespace to group every component common to `TransactionReview` and `PreAuthorizationReview` +enum InteractionReviewCommon {} + +// MARK: InteractionReviewCommon.Kind +extension InteractionReviewCommon { + enum Kind: Sendable, Hashable { + case transaction + case preAuthorization + } +} diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/RawTransactionView.swift b/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/RawTransactionView.swift new file mode 100644 index 0000000000..ac5a31b4cf --- /dev/null +++ b/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/RawTransactionView.swift @@ -0,0 +1,64 @@ +import SwiftUI + +extension InteractionReviewCommon { + struct RawTransactionView: SwiftUI.View { + let transaction: String + let copyAction: () -> Void + let toggleAction: (() -> Void)? + + init( + transaction: String, + copyAction: @escaping () -> Void, + toggleAction: (() -> Void)? = nil + ) { + self.transaction = transaction + self.copyAction = copyAction + self.toggleAction = toggleAction + } + + var body: some View { + VStack(alignment: .leading, spacing: .medium1) { + HStack(spacing: .small1) { // TODO: confirm spacing + Spacer() + copyButton + toggleButton + } + + content + .padding(.horizontal, .small1) + } + .padding([.top, .horizontal], .medium3) + .padding(.bottom, .medium1) + .frame(maxWidth: .infinity) + } + + private var copyButton: some View { + Button(action: copyAction) { + HStack(spacing: .small3) { + AssetIcon(.asset(AssetResource.copy)) + Text(L10n.Common.copy) + .textStyle(.body1Header) + } + .foregroundColor(.app.gray1) + } + .buttonStyle(.secondaryRectangular) + } + + private var toggleButton: some View { + Group { + if let toggleAction { + Button(asset: AssetResource.iconTxnBlocks, action: toggleAction) + .buttonStyle(.secondaryRectangular) + } + } + } + + private var content: some View { + Text(transaction) + .textStyle(.monospace) + .foregroundColor(.app.gray1) + .multilineTextAlignment(.leading) + .textSelection(.enabled) + } + } +} diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index 52902f9f5b..553fda210c 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -44,9 +44,10 @@ extension PreAuthorizationReview { VStack(spacing: .zero) { header - ForEach(0 ..< 30) { index in - Text("Row \(index)") - .padding() + if let rawContent = store.displayMode.rawTransaction { + rawTransaction(rawContent) + } else { + details } Spacer() @@ -67,7 +68,7 @@ extension PreAuthorizationReview { } private var header: some SwiftUI.View { - InteractionReview.HeaderView( + Common.HeaderView( kind: .preAuthorization, name: store.dappName, thumbnail: nil @@ -76,5 +77,13 @@ extension PreAuthorizationReview { .padding(.horizontal, .medium3) .padding(.bottom, .medium3) } + + private func rawTransaction(_ content: String) -> some SwiftUI.View { + Common.RawTransactionView(transaction: content) {} toggleAction: {} + } + + private var details: some SwiftUI.View { + VStack(spacing: .medium1) {} + } } } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 43808b4e4d..02f55ca521 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -1,9 +1,12 @@ // MARK: - PreAuthorizationReview @Reducer struct PreAuthorizationReview: Sendable, FeatureReducer { + typealias Common = InteractionReviewCommon + @ObservableState struct State: Sendable, Hashable { var dappName: String? = "Collabo.Fi" + var displayMode: Common.DisplayMode = .detailed init() {} } diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index 27bfe58e71..3b9daa77e9 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -152,7 +152,7 @@ extension TransactionReview { header(viewStore.proposingDappMetadata) if let rawTransaction = viewStore.rawTransaction { - RawTransactionView(transaction: rawTransaction) { + Common.RawTransactionView(transaction: rawTransaction) { viewStore.send(.copyRawTransactionTapped) } } else { @@ -246,7 +246,7 @@ extension TransactionReview { } private func header(_ proposingDappMetadata: DappMetadata.Ledger?) -> some SwiftUI.View { - InteractionReview.HeaderView( + Common.HeaderView( kind: .transaction, name: proposingDappMetadata?.name?.rawValue, thumbnail: proposingDappMetadata?.thumbnail @@ -634,40 +634,6 @@ struct TransactionMessageView: View { } } -// MARK: - RawTransactionView -struct RawTransactionView: SwiftUI.View { - let transaction: String - let copyTapped: () -> Void - - var body: some SwiftUI.View { - VStack(alignment: .trailing) { - Button(action: copyTapped) { - HStack(spacing: .small3) { - AssetIcon(.asset(AssetResource.copy)) - Text(L10n.Common.copy) - .textStyle(.body1Header) - } - .foregroundColor(.app.gray1) - } - .buttonStyle(.secondaryRectangular) - .padding([.trailing, .top], .medium3) - .padding(.bottom, .medium1) - - Text(transaction) - .textSelection(.enabled) - .textStyle(.monospace) - .multilineTextAlignment(.leading) - .foregroundColor(.app.gray1) - .frame( - maxWidth: .infinity, - maxHeight: .infinity, - alignment: .topLeading - ) - .padding([.horizontal, .bottom], .medium1) - } - } -} - extension StrokeStyle { static let transactionReview = StrokeStyle(lineWidth: 2, dash: [5, 5]) } diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift index ab59f585af..c16d939b39 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift @@ -4,9 +4,10 @@ import SwiftUI // MARK: - TransactionReview public struct TransactionReview: Sendable, FeatureReducer { public typealias Transfer = IDResourceBalance + typealias Common = InteractionReviewCommon public struct State: Sendable, Hashable { - public var displayMode: DisplayMode = .review + var displayMode: Common.DisplayMode = .detailed public let nonce: Nonce public let unvalidatedManifest: UnvalidatedTransactionManifest @@ -94,16 +95,6 @@ public struct TransactionReview: Sendable, FeatureReducer { self.proposingDappMetadata = proposingDappMetadata self.p2pRoute = p2pRoute } - - public enum DisplayMode: Sendable, Hashable { - case review - case raw(String) - - var rawTransaction: String? { - guard case let .raw(transaction) = self else { return nil } - return transaction - } - } } public enum ViewAction: Sendable, Equatable { @@ -271,10 +262,10 @@ public struct TransactionReview: Sendable, FeatureReducer { case .showRawTransactionTapped: switch state.displayMode { - case .review: + case .detailed: return showRawTransaction(&state) case .raw: - state.displayMode = .review + state.displayMode = .detailed return .none } From 24e88196691a687955fb1d9c9146c4c9dcca1332 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Thu, 17 Oct 2024 15:38:36 +0200 Subject: [PATCH 04/63] WIP --- RadixWallet.xcodeproj/project.pbxproj | 8 ++++ .../InteractionReviewCommon+Extra.swift | 12 +++++ .../RawTransactionView.swift | 2 +- .../TransferLineView.swift | 19 ++++++++ .../PreAuthorizationReview+View.swift | 25 ++++++++--- .../PreAuthorizationReview.swift | 44 ++++++++++++++++++- .../TransactionReview+View.swift | 20 +++------ 7 files changed, 108 insertions(+), 22 deletions(-) create mode 100644 RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/InteractionReviewCommon+Extra.swift create mode 100644 RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/TransferLineView.swift diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index a027b2fab5..8a6f4c841b 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -712,6 +712,8 @@ 48FFFB0D2ADC744700B2B213 /* TextBuilder in Frameworks */ = {isa = PBXBuildFile; productRef = 48FFFB0C2ADC744700B2B213 /* TextBuilder */; }; 5B03E3CF2CC1223000E10A64 /* DisplayMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B03E3CE2CC1222D00E10A64 /* DisplayMode.swift */; }; 5B03E3D12CC127B100E10A64 /* RawTransactionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */; }; + 5B03E3D32CC141D100E10A64 /* InteractionReviewCommon+Extra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B03E3D22CC141C200E10A64 /* InteractionReviewCommon+Extra.swift */; }; + 5B03E3D52CC1487900E10A64 /* TransferLineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */; }; 5B135B392C7636DA004AAD2E /* HiddenEntities+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B135B382C7636DA004AAD2E /* HiddenEntities+View.swift */; }; 5B135B3B2C7636FD004AAD2E /* HiddenEntities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B135B3A2C7636FD004AAD2E /* HiddenEntities.swift */; }; 5B1C4FD52BBB0B0C00B9436F /* AppsFlyerLib-Strict in Frameworks */ = {isa = PBXBuildFile; productRef = 5B1C4FD42BBB0B0C00B9436F /* AppsFlyerLib-Strict */; }; @@ -1932,6 +1934,8 @@ 48FFFAF12ADC23AC00B2B213 /* Exports.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Exports.swift; sourceTree = ""; }; 5B03E3CE2CC1222D00E10A64 /* DisplayMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayMode.swift; sourceTree = ""; }; 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawTransactionView.swift; sourceTree = ""; }; + 5B03E3D22CC141C200E10A64 /* InteractionReviewCommon+Extra.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InteractionReviewCommon+Extra.swift"; sourceTree = ""; }; + 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransferLineView.swift; sourceTree = ""; }; 5B135B382C7636DA004AAD2E /* HiddenEntities+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HiddenEntities+View.swift"; sourceTree = ""; }; 5B135B3A2C7636FD004AAD2E /* HiddenEntities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HiddenEntities.swift; sourceTree = ""; }; 5B1C4FD72BBB0C1E00B9436F /* AppsFlyerClient+Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppsFlyerClient+Interface.swift"; sourceTree = ""; }; @@ -5543,6 +5547,8 @@ 5B4A1AC22CC0120600679EE6 /* InteractionReviewCommon */ = { isa = PBXGroup; children = ( + 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */, + 5B03E3D22CC141C200E10A64 /* InteractionReviewCommon+Extra.swift */, 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */, 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */, 5B03E3CE2CC1222D00E10A64 /* DisplayMode.swift */, @@ -7533,6 +7539,7 @@ A40816152C7E0D08005E65B9 /* StateEntityMetadataPageRequest.swift in Sources */, 48CFC5972ADC10DA00E77A5C /* ToggleView.swift in Sources */, 5B634AB02C92F6FA004B2FBC /* UpdateP2PLinkName+View.swift in Sources */, + 5B03E3D32CC141D100E10A64 /* InteractionReviewCommon+Extra.swift in Sources */, 48CFC4892ADC10DA00E77A5C /* EntityMetadata+GWMetadata.swift in Sources */, 48CFC3512ADC10D900E77A5C /* DappHeader.swift in Sources */, A40815742C7E0D08005E65B9 /* EntityNotFoundError.swift in Sources */, @@ -7623,6 +7630,7 @@ A40815B72C7E0D08005E65B9 /* NativeResourceRedemptionValueItem.swift in Sources */, 48CFC29A2ADC10D900E77A5C /* TransactionReviewDapps+View.swift in Sources */, 483A3DE62BD2678900055932 /* Stage1MigrateToSargon+FactorSourceCryptoParameters.swift in Sources */, + 5B03E3D52CC1487900E10A64 /* TransferLineView.swift in Sources */, 48CFC36B2ADC10D900E77A5C /* FungibleTokenDetails+Reducer.swift in Sources */, 5BBC7D9F2C3D390E00B04BD6 /* BootstrapClient+Live.swift in Sources */, 5B135B392C7636DA004AAD2E /* HiddenEntities+View.swift in Sources */, diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/InteractionReviewCommon+Extra.swift b/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/InteractionReviewCommon+Extra.swift new file mode 100644 index 0000000000..b30db293a9 --- /dev/null +++ b/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/InteractionReviewCommon+Extra.swift @@ -0,0 +1,12 @@ +extension InteractionReviewCommon { + static let gradientBackground: LinearGradient = .init( + stops: [ + .init(color: .app.gray5, location: 0), + .init(color: .app.gray4, location: 1), + ], + startPoint: .top, + endPoint: .bottom + ) + + static let transferLineTrailingPadding: CGFloat = .huge3 +} diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/RawTransactionView.swift b/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/RawTransactionView.swift index ac5a31b4cf..40997a0216 100644 --- a/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/RawTransactionView.swift +++ b/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/RawTransactionView.swift @@ -18,7 +18,7 @@ extension InteractionReviewCommon { var body: some View { VStack(alignment: .leading, spacing: .medium1) { - HStack(spacing: .small1) { // TODO: confirm spacing + HStack(spacing: .small2) { Spacer() copyButton toggleButton diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/TransferLineView.swift b/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/TransferLineView.swift new file mode 100644 index 0000000000..6e71aba660 --- /dev/null +++ b/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/TransferLineView.swift @@ -0,0 +1,19 @@ +import SwiftUI + +extension InteractionReviewCommon { + typealias Common = InteractionReviewCommon + + struct TransferLineView: View { + var body: some View { + VLine() + .stroke(.app.gray3, style: .interactionReview) + .frame(width: 1) + .padding(.trailing, Common.transferLineTrailingPadding) + .padding(.top, -.medium1) + } + } +} + +private extension StrokeStyle { + static let interactionReview = StrokeStyle(lineWidth: 2, dash: [5, 5]) +} diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index 553fda210c..148cf350e3 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -44,11 +44,16 @@ extension PreAuthorizationReview { VStack(spacing: .zero) { header - if let rawContent = store.displayMode.rawTransaction { - rawTransaction(rawContent) - } else { - details + Group { + if let rawContent = store.displayMode.rawTransaction { + rawTransaction(rawContent) + } else { + details + } } + .padding(.horizontal, .small2) + .background(Common.gradientBackground) + .clipShape(RoundedRectangle(cornerRadius: .small1)) Spacer() } @@ -79,7 +84,11 @@ extension PreAuthorizationReview { } private func rawTransaction(_ content: String) -> some SwiftUI.View { - Common.RawTransactionView(transaction: content) {} toggleAction: {} + Common.RawTransactionView(transaction: content) { + store.send(.view(.copyRawTransactionButtonTapped)) + } toggleAction: { + store.send(.view(.toggleDisplayModeButtonTapped)) + } } private var details: some SwiftUI.View { @@ -87,3 +96,9 @@ extension PreAuthorizationReview { } } } + +extension PreAuthorizationReview.State { + var showTransferLine: Bool { + true + } +} diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 02f55ca521..e0f6f988ed 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -14,6 +14,8 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { enum ViewAction: Sendable, Equatable { case appeared + case toggleDisplayModeButtonTapped + case copyRawTransactionButtonTapped } var body: some ReducerOf { @@ -23,7 +25,47 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { func reduce(into state: inout State, viewAction: ViewAction) -> Effect { switch viewAction { case .appeared: - .none + return .none + case .toggleDisplayModeButtonTapped: + switch state.displayMode { + case .detailed: + state.displayMode = .raw(state.exampleRaw) + case .raw: + state.displayMode = .detailed + } + return .none + case .copyRawTransactionButtonTapped: + return .none } } } + +extension PreAuthorizationReview.State { + var exampleRaw: String { + """ + CALL_METHOD + Address("account_tdx_2_12ytkalad6hfxamsz4a7r8tevz7ahurfj58dlp4phl4nca5hs0hpu90") + "lock_fee" + Decimal("0.3696274912355") + ; + CALL_METHOD + Address("account_tdx_2_12ytkalad6hfxamsz4a7r8tevz7ahurfj58dlp4phl4nca5hs0hpu90") + "withdraw" + Address("resource_tdx_2_1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxtfd2jc") + Decimal("2") + ; + TAKE_FROM_WORKTOP + Address("resource_tdx_2_1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxtfd2jc") + Decimal("2") + Bucket("bucket1") + ; + CALL_METHOD + Address("account_tdx_2_12x2hd6m7z9n389u47sn7qhv3cmeqseyathrpqa2mwlx8wczrpd36ar") + "try_deposit_or_abort" + Bucket("bucket1") + Enum<0u8>() + ; + + """ + } +} diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index 3b9daa77e9..2aec7e0253 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -1,10 +1,6 @@ import ComposableArchitecture import SwiftUI -private extension CGFloat { - static let transferLineTrailingPadding = CGFloat.huge3 -} - extension View { var sectionHeading: some View { textStyle(.body1Header) @@ -184,11 +180,7 @@ extension TransactionReview { } .background(alignment: .trailing) { if viewStore.showTransferLine { - VLine() - .stroke(.app.gray3, style: .transactionReview) - .frame(width: 1) - .padding(.trailing, .transferLineTrailingPadding) - .padding(.top, -.medium1) + Common.TransferLineView() } } @@ -228,7 +220,7 @@ extension TransactionReview { JaggedEdge(shadowColor: shadowColor, isTopEdge: false) } } - .background(.app.gray5.gradient.shadow(.inner(color: shadowColor, radius: 15))) + .background(Common.gradientBackground) .animation(.easeInOut, value: viewStore.canToggleViewMode ? viewStore.rawTransaction : nil) } .coordinateSpace(name: coordSpace) @@ -516,6 +508,8 @@ private extension View { // MARK: - ExpandableTransactionHeading struct ExpandableTransactionHeading: View { + typealias Common = InteractionReviewCommon + let heading: TransactionHeading let isExpanded: Bool let action: () -> Void @@ -531,7 +525,7 @@ struct ExpandableTransactionHeading: View { Spacer(minLength: 0) } } - .padding(.trailing, .transferLineTrailingPadding + .small3) // padding from the vertical dotted line + .padding(.trailing, Common.transferLineTrailingPadding + .small3) // padding from the vertical dotted line } } @@ -634,10 +628,6 @@ struct TransactionMessageView: View { } } -extension StrokeStyle { - static let transactionReview = StrokeStyle(lineWidth: 2, dash: [5, 5]) -} - extension TransactionReview { public typealias ValidatorsState = ValidatorsView.ViewState public typealias ValidatorState = ValidatorView.ViewState From 3778a7f0f1eba3cf0cdd4176c7ef38b3c20e8476 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 21 Oct 2024 09:10:16 -0300 Subject: [PATCH 05/63] WIP --- RadixWallet.xcodeproj/project.pbxproj | 58 ++++++----- .../icon-txn-blocks.pdf | Bin 1775 -> 1775 bytes .../InteractionReviewCommon/HeadingView.swift | 86 +++++++++++++++ .../PreAuthorizationReview+View.swift | 29 +++++- .../TransactionReview+View.swift | 98 ++---------------- 5 files changed, 151 insertions(+), 120 deletions(-) create mode 100644 RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/HeadingView.swift diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index 85770bc570..ed48cd7f09 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -721,6 +721,7 @@ 5B272DD72C36E89600B74F1F /* AppEventsClient+Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B272DD62C36E89600B74F1F /* AppEventsClient+Interface.swift */; }; 5B272DD92C36E93100B74F1F /* AppEventsClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B272DD82C36E93100B74F1F /* AppEventsClient+Live.swift */; }; 5B272DDB2C36E9D300B74F1F /* AppEventsClient+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B272DDA2C36E9D300B74F1F /* AppEventsClient+Test.swift */; }; + 5B27FBD92CC67655002975BE /* HeadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBD82CC67655002975BE /* HeadingView.swift */; }; 5B2A45022BD6680400AEC8AD /* ContactSupportClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */; }; 5B2A45042BD6689100AEC8AD /* ContactSupportClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */; }; 5B3C48A92C7E190C00DB160D /* AssetRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B3C48A82C7E190C00DB160D /* AssetRow.swift */; }; @@ -738,14 +739,14 @@ 5B45E2FF2BC59780007C4C84 /* SignWithFactorSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B45E2FD2BC59780007C4C84 /* SignWithFactorSource.swift */; }; 5B45E3012BC5A491007C4C84 /* FactorSourceAccess+ViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B45E3002BC5A491007C4C84 /* FactorSourceAccess+ViewState.swift */; }; 5B4712CC2C526146003B4712 /* HeaderButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4712CB2C526146003B4712 /* HeaderButtonStyle.swift */; }; - 5B4A1ABF2CC00FB800679EE6 /* PreAuthorizationReview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */; }; - 5B4A1AC02CC00FB800679EE6 /* PreAuthorizationReview+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */; }; - 5B4A1AC42CC0125700679EE6 /* InteractionReview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */; }; - 5B4A1AC62CC0151300679EE6 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */; }; 5B4A1AB32CBFC99200679EE6 /* SignProofOfOwnership.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AB22CBFC98B00679EE6 /* SignProofOfOwnership.swift */; }; 5B4A1AB62CBFCFCF00679EE6 /* SignProofOfOwnership+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AB52CBFCFC200679EE6 /* SignProofOfOwnership+View.swift */; }; 5B4A1ABA2CBFEBB000679EE6 /* ProofOfOwnership+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AB92CBFEBB000679EE6 /* ProofOfOwnership+View.swift */; }; 5B4A1ABB2CBFEBB000679EE6 /* ProofOfOwnership.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AB82CBFEBB000679EE6 /* ProofOfOwnership.swift */; }; + 5B4A1ABF2CC00FB800679EE6 /* PreAuthorizationReview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */; }; + 5B4A1AC02CC00FB800679EE6 /* PreAuthorizationReview+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */; }; + 5B4A1AC42CC0125700679EE6 /* InteractionReview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */; }; + 5B4A1AC62CC0151300679EE6 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */; }; 5B4E1D132CB421EB002FAC2E /* DepositStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4E1D122CB421E3002FAC2E /* DepositStatus.swift */; }; 5B4E1D1F2CB7FE8E002FAC2E /* Sargon in Frameworks */ = {isa = PBXBuildFile; productRef = 5B4E1D1E2CB7FE8E002FAC2E /* Sargon */; }; 5B526ADB2C876E7C00AF8B72 /* AccountLockerClaimDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B526ADA2C876E7C00AF8B72 /* AccountLockerClaimDetails.swift */; }; @@ -1949,6 +1950,7 @@ 5B272DD62C36E89600B74F1F /* AppEventsClient+Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppEventsClient+Interface.swift"; sourceTree = ""; }; 5B272DD82C36E93100B74F1F /* AppEventsClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppEventsClient+Live.swift"; sourceTree = ""; }; 5B272DDA2C36E9D300B74F1F /* AppEventsClient+Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppEventsClient+Test.swift"; sourceTree = ""; }; + 5B27FBD82CC67655002975BE /* HeadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadingView.swift; sourceTree = ""; }; 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactSupportClient.swift; sourceTree = ""; }; 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactSupportClient+Live.swift"; sourceTree = ""; }; 5B3C48A82C7E190C00DB160D /* AssetRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetRow.swift; sourceTree = ""; }; @@ -1965,14 +1967,14 @@ 5B45E2FD2BC59780007C4C84 /* SignWithFactorSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignWithFactorSource.swift; sourceTree = ""; }; 5B45E3002BC5A491007C4C84 /* FactorSourceAccess+ViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FactorSourceAccess+ViewState.swift"; sourceTree = ""; }; 5B4712CB2C526146003B4712 /* HeaderButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderButtonStyle.swift; sourceTree = ""; }; - 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreAuthorizationReview.swift; sourceTree = ""; }; - 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationReview+View.swift"; sourceTree = ""; }; - 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractionReview.swift; sourceTree = ""; }; - 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = ""; }; 5B4A1AB22CBFC98B00679EE6 /* SignProofOfOwnership.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignProofOfOwnership.swift; sourceTree = ""; }; 5B4A1AB52CBFCFC200679EE6 /* SignProofOfOwnership+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SignProofOfOwnership+View.swift"; sourceTree = ""; }; 5B4A1AB82CBFEBB000679EE6 /* ProofOfOwnership.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProofOfOwnership.swift; sourceTree = ""; }; 5B4A1AB92CBFEBB000679EE6 /* ProofOfOwnership+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProofOfOwnership+View.swift"; sourceTree = ""; }; + 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreAuthorizationReview.swift; sourceTree = ""; }; + 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationReview+View.swift"; sourceTree = ""; }; + 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractionReview.swift; sourceTree = ""; }; + 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = ""; }; 5B4E1D122CB421E3002FAC2E /* DepositStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepositStatus.swift; sourceTree = ""; }; 5B526ADA2C876E7C00AF8B72 /* AccountLockerClaimDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountLockerClaimDetails.swift; sourceTree = ""; }; 5B526AE82C89C3C200AF8B72 /* ResourcesVisibilityClient+Interface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ResourcesVisibilityClient+Interface.swift"; sourceTree = ""; }; @@ -5548,6 +5550,25 @@ path = FactorSourceAccess; sourceTree = ""; }; + 5B4A1AB42CBFCFA100679EE6 /* SignProofOfOwnership */ = { + isa = PBXGroup; + children = ( + 5B4A1AB22CBFC98B00679EE6 /* SignProofOfOwnership.swift */, + 5B4A1AB52CBFCFC200679EE6 /* SignProofOfOwnership+View.swift */, + ); + path = SignProofOfOwnership; + sourceTree = ""; + }; + 5B4A1AB72CBFEB9700679EE6 /* ProofOfOwnership */ = { + isa = PBXGroup; + children = ( + 5B4A1AB82CBFEBB000679EE6 /* ProofOfOwnership.swift */, + 5B4A1AB92CBFEBB000679EE6 /* ProofOfOwnership+View.swift */, + 5B4A1AB42CBFCFA100679EE6 /* SignProofOfOwnership */, + ); + path = ProofOfOwnership; + sourceTree = ""; + }; 5B4A1ABC2CC00F7F00679EE6 /* PreAuthorizationReview */ = { isa = PBXGroup; children = ( @@ -5561,6 +5582,7 @@ 5B4A1AC22CC0120600679EE6 /* InteractionReviewCommon */ = { isa = PBXGroup; children = ( + 5B27FBD82CC67655002975BE /* HeadingView.swift */, 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */, 5B03E3D22CC141C200E10A64 /* InteractionReviewCommon+Extra.swift */, 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */, @@ -5571,25 +5593,6 @@ path = InteractionReviewCommon; sourceTree = ""; }; - 5B4A1AB42CBFCFA100679EE6 /* SignProofOfOwnership */ = { - isa = PBXGroup; - children = ( - 5B4A1AB22CBFC98B00679EE6 /* SignProofOfOwnership.swift */, - 5B4A1AB52CBFCFC200679EE6 /* SignProofOfOwnership+View.swift */, - ); - path = SignProofOfOwnership; - sourceTree = ""; - }; - 5B4A1AB72CBFEB9700679EE6 /* ProofOfOwnership */ = { - isa = PBXGroup; - children = ( - 5B4A1AB82CBFEBB000679EE6 /* ProofOfOwnership.swift */, - 5B4A1AB92CBFEBB000679EE6 /* ProofOfOwnership+View.swift */, - 5B4A1AB42CBFCFA100679EE6 /* SignProofOfOwnership */, - ); - path = ProofOfOwnership; - sourceTree = ""; - }; 5B526AEB2C89C3C200AF8B72 /* ResourcesVisibilityClient */ = { isa = PBXGroup; children = ( @@ -7565,6 +7568,7 @@ A408158A2C7E0D08005E65B9 /* MetadataBoolValue.swift in Sources */, A40815F52C7E0D08005E65B9 /* ResourceHoldersResponse.swift in Sources */, 834B651F2B972E5100B7E1E8 /* NPSSurvey.swift in Sources */, + 5B27FBD92CC67655002975BE /* HeadingView.swift in Sources */, 48CFC26A2ADC10D900E77A5C /* Signing+View.swift in Sources */, 48CFC3262ADC10D900E77A5C /* LocalNetworkPermission+Reducer.swift in Sources */, E657773D2B0BAB35002DB237 /* RecoverWalletControlWithBDFSOnly.swift in Sources */, diff --git a/RadixWallet/Core/Resources/Resources/Assets.xcassets/Common/icon-txn-blocks.imageset/icon-txn-blocks.pdf b/RadixWallet/Core/Resources/Resources/Assets.xcassets/Common/icon-txn-blocks.imageset/icon-txn-blocks.pdf index f40943750ade0e23b67853ad68f8f4f813373a24..843b81f6e2a4807f269a915fb87219fa95960438 100644 GIT binary patch delta 35 mcmaFQ`<{2gLJ0#fP%zLlw6HKTHU%<_O$-gq%{J~dV*>!Wi3xQ8 delta 35 ocmaFQ`<{2gLJ3n70|PTl1p_@(GXrA_5W~#G(9Fzy<4!X+0K8KPnE(I) diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/HeadingView.swift b/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/HeadingView.swift new file mode 100644 index 0000000000..cfa4ec68f6 --- /dev/null +++ b/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/HeadingView.swift @@ -0,0 +1,86 @@ +import SwiftUI + +extension InteractionReviewCommon { + struct HeadingView: View { + let heading: String + let icon: ImageAsset + + init(_ heading: String, icon: ImageAsset) { + self.heading = heading + self.icon = icon + } + + var body: some View { + HStack(spacing: .small2) { + Image(asset: icon) + .padding(.small3) + .overlay { + Circle() + .stroke(style: StrokeStyle(lineWidth: 1, dash: [3, 3])) + .foregroundColor(.app.gray3) + } + Text(heading) + .minimumScaleFactor(0.7) + .multilineTextAlignment(.leading) + .lineSpacing(0) + .sectionHeading + .textCase(.uppercase) + } + } + + static let message = HeadingView( + L10n.TransactionReview.messageHeading, + icon: AssetResource.transactionReviewMessage + ) + + static let withdrawing = HeadingView( + L10n.TransactionReview.withdrawalsHeading, + icon: AssetResource.transactionReviewWithdrawing + ) + + static let depositing = HeadingView( + L10n.TransactionReview.depositsHeading, + icon: AssetResource.transactionReviewDepositing + ) + + static let usingDapps = HeadingView( + L10n.TransactionReview.usingDappsHeading, + icon: AssetResource.transactionReviewDapps + ) + + static let contributingToPools = HeadingView( + L10n.TransactionReview.poolContributionHeading, + icon: AssetResource.transactionReviewPools + ) + + static let redeemingFromPools = HeadingView( + L10n.TransactionReview.poolRedemptionHeading, + icon: AssetResource.transactionReviewPools + ) + + static let stakingToValidators = HeadingView( + L10n.TransactionReview.stakingToValidatorsHeading, + icon: AssetResource.iconValidator + ) + + static let unstakingFromValidators = HeadingView( + L10n.TransactionReview.unstakingFromValidatorsHeading, + icon: AssetResource.iconValidator + ) + + static let claimingFromValidators = HeadingView( + L10n.TransactionReview.claimFromValidatorsHeading, + icon: AssetResource.iconValidator + ) + + static let depositSetting = HeadingView( + L10n.TransactionReview.thirdPartyDepositSettingHeading, + icon: AssetResource.transactionReviewDepositSetting + ) + + static let depositExceptions = HeadingView( + L10n.TransactionReview.thirdPartyDepositExceptionsHeading, + icon: AssetResource.transactionReviewDepositSetting + ) + } +} diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index 148cf350e3..768eac852f 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -51,12 +51,13 @@ extension PreAuthorizationReview { details } } - .padding(.horizontal, .small2) .background(Common.gradientBackground) .clipShape(RoundedRectangle(cornerRadius: .small1)) + .padding(.horizontal, .small2) Spacer() } + .animation(.easeInOut, value: store.displayMode.rawTransaction) } .coordinateSpace(name: coordSpace) .onPreferenceChange(PositionsPreferenceKey.self) { positions in @@ -92,7 +93,31 @@ extension PreAuthorizationReview { } private var details: some SwiftUI.View { - VStack(spacing: .medium1) {} + VStack(alignment: .leading, spacing: .medium1) { + Common.HeadingView.withdrawing + + VStack(alignment: .leading, spacing: .medium1) { + Common.HeadingView.contributingToPools + + Common.HeadingView.redeemingFromPools + } + .frame(maxWidth: .infinity, alignment: .leading) // necessary? + .background(alignment: .trailing) { + if store.showTransferLine { + Common.TransferLineView() + } + } + } + .padding(.top, .large2 + .small3) + .padding(.horizontal, .small1) + .padding(.bottom, .medium1) + .overlay(alignment: .topTrailing) { + Button(asset: AssetResource.code) { + store.send(.view(.toggleDisplayModeButtonTapped)) + } + .buttonStyle(.secondaryRectangular) + .padding(.medium3) + } } } } diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index fa0c23d75b..3e66f3ea28 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -255,7 +255,7 @@ extension TransactionReview { private func messageSection(with message: String?) -> some SwiftUI.View { if let message { VStack(alignment: .leading, spacing: .small2) { - TransactionHeading.message + Common.HeadingView.message TransactionMessageView(message: message) } } @@ -264,7 +264,7 @@ extension TransactionReview { private var withdrawalsSection: some SwiftUI.View { IfLetStore(store.scope(state: \.withdrawals) { .child(.withdrawals($0)) }) { childStore in VStack(alignment: .leading, spacing: .small2) { - TransactionHeading.withdrawing + Common.HeadingView.withdrawing TransactionReviewAccounts.View(store: childStore) } } @@ -333,7 +333,7 @@ extension TransactionReview { private var depositsSection: some SwiftUI.View { IfLetStore(store.scope(state: \.deposits) { .child(.deposits($0)) }) { childStore in VStack(alignment: .leading, spacing: .small2) { - TransactionHeading.depositing + Common.HeadingView.depositing TransactionReviewAccounts.View(store: childStore) } } @@ -342,7 +342,7 @@ extension TransactionReview { @ViewBuilder private func accountDepositSettingSection(_ viewState: DepositSettingState) -> some SwiftUI.View { VStack(alignment: .leading, spacing: .small2) { - TransactionHeading.depositSetting + Common.HeadingView.depositSetting DepositSettingView(viewState: viewState) } } @@ -350,7 +350,7 @@ extension TransactionReview { @ViewBuilder private func accountDepositExceptionsSection(_ viewState: DepositExceptionsState) -> some SwiftUI.View { VStack(alignment: .leading, spacing: .small2) { - TransactionHeading.depositExceptions + Common.HeadingView.depositExceptions DepositExceptionsView(viewState: viewState) } } @@ -510,7 +510,7 @@ private extension View { struct ExpandableTransactionHeading: View { typealias Common = InteractionReviewCommon - let heading: TransactionHeading + let heading: Common.HeadingView let isExpanded: Bool let action: () -> Void @@ -529,90 +529,6 @@ struct ExpandableTransactionHeading: View { } } -// MARK: - TransactionHeading -struct TransactionHeading: View { - let heading: String - let icon: ImageAsset - - init(_ heading: String, icon: ImageAsset) { - self.heading = heading - self.icon = icon - } - - var body: some View { - HStack(spacing: .small2) { - Image(asset: icon) - .padding(.small3) - .overlay { - Circle() - .stroke(style: StrokeStyle(lineWidth: 1, dash: [3, 3])) - .foregroundColor(.app.gray3) - } - Text(heading) - .minimumScaleFactor(0.7) - .multilineTextAlignment(.leading) - .lineSpacing(0) - .sectionHeading - .textCase(.uppercase) - } - } - - static let message = TransactionHeading( - L10n.TransactionReview.messageHeading, - icon: AssetResource.transactionReviewMessage - ) - - static let withdrawing = TransactionHeading( - L10n.TransactionReview.withdrawalsHeading, - icon: AssetResource.transactionReviewWithdrawing - ) - - static let depositing = TransactionHeading( - L10n.TransactionReview.depositsHeading, - icon: AssetResource.transactionReviewDepositing - ) - - static let usingDapps = TransactionHeading( - L10n.TransactionReview.usingDappsHeading, - icon: AssetResource.transactionReviewDapps - ) - - static let contributingToPools = TransactionHeading( - L10n.TransactionReview.poolContributionHeading, - icon: AssetResource.transactionReviewPools - ) - - static let redeemingFromPools = TransactionHeading( - L10n.TransactionReview.poolRedemptionHeading, - icon: AssetResource.transactionReviewPools - ) - - static let stakingToValidators = TransactionHeading( - L10n.TransactionReview.stakingToValidatorsHeading, - icon: AssetResource.iconValidator - ) - - static let unstakingFromValidators = TransactionHeading( - L10n.TransactionReview.unstakingFromValidatorsHeading, - icon: AssetResource.iconValidator - ) - - static let claimingFromValidators = TransactionHeading( - L10n.TransactionReview.claimFromValidatorsHeading, - icon: AssetResource.iconValidator - ) - - static let depositSetting = TransactionHeading( - L10n.TransactionReview.thirdPartyDepositSettingHeading, - icon: AssetResource.transactionReviewDepositSetting - ) - - static let depositExceptions = TransactionHeading( - L10n.TransactionReview.thirdPartyDepositExceptionsHeading, - icon: AssetResource.transactionReviewDepositSetting - ) -} - // MARK: - TransactionMessageView struct TransactionMessageView: View { let message: String @@ -633,7 +549,7 @@ extension TransactionReview { typealias ValidatorState = ValidatorView.ViewState struct ValidatorsView: SwiftUI.View { - let heading: TransactionHeading + let heading: InteractionReviewCommon.HeadingView let viewState: ViewState let action: () -> Void From 957b8a308240a0d5d166f0a5cba548f7b7fddaa7 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 21 Oct 2024 10:00:01 -0300 Subject: [PATCH 06/63] WIP --- .../PreAuthorizationReview+View.swift | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index 768eac852f..53c483e342 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -55,6 +55,10 @@ extension PreAuthorizationReview { .clipShape(RoundedRectangle(cornerRadius: .small1)) .padding(.horizontal, .small2) + feesInformation + .padding(.top, .small2) + .padding(.horizontal, .small2) + Spacer() } .animation(.easeInOut, value: store.displayMode.rawTransaction) @@ -119,6 +123,27 @@ extension PreAuthorizationReview { .padding(.medium3) } } + + private var feesInformation: some SwiftUI.View { + HStack(spacing: .zero) { + VStack(alignment: .leading, spacing: .zero) { + Text("Pre-authorization will be returned to \(store.dappName ?? "dApp") for processing.") + .foregroundStyle(.app.gray1) + + Text("Network fees will be paid by the dApp") + .foregroundStyle(.app.gray2) + } + .textStyle(.body2Regular) + + Spacer(minLength: .small2) + + InfoButton(.dapps) + } + .padding(.vertical, .medium3) + .padding(.horizontal, .medium2) + .background(Color.app.gray5) + .clipShape(RoundedRectangle(cornerRadius: .small1)) + } } } From bf90c75a045e789e94c7e796b7076c9a56c97224 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 21 Oct 2024 11:16:35 -0300 Subject: [PATCH 07/63] WIP --- RadixWallet.xcodeproj/project.pbxproj | 4 +- .../PreAuthorizationReview+View.swift | 81 ++++++++++++++++++- .../PreAuthorizationReview.swift | 57 ++++++++++++- 3 files changed, 136 insertions(+), 6 deletions(-) diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index ed48cd7f09..4e3e8c8fae 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -5582,11 +5582,11 @@ 5B4A1AC22CC0120600679EE6 /* InteractionReviewCommon */ = { isa = PBXGroup; children = ( + 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */, + 5B03E3D22CC141C200E10A64 /* InteractionReviewCommon+Extra.swift */, 5B27FBD82CC67655002975BE /* HeadingView.swift */, 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */, - 5B03E3D22CC141C200E10A64 /* InteractionReviewCommon+Extra.swift */, 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */, - 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */, 5B03E3CE2CC1222D00E10A64 /* DisplayMode.swift */, 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */, ); diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index 53c483e342..4623e14e6e 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -22,6 +22,9 @@ extension PreAuthorizationReview { } } } + .onAppear { + store.send(.view(.appeared)) + } } } @@ -59,7 +62,9 @@ extension PreAuthorizationReview { .padding(.top, .small2) .padding(.horizontal, .small2) - Spacer() + expiration + + slider } .animation(.easeInOut, value: store.displayMode.rawTransaction) } @@ -137,18 +142,88 @@ extension PreAuthorizationReview { Spacer(minLength: .small2) - InfoButton(.dapps) + InfoButton(.dapps) // TODO: Update to correct one } .padding(.vertical, .medium3) .padding(.horizontal, .medium2) .background(Color.app.gray5) .clipShape(RoundedRectangle(cornerRadius: .small1)) } + + private var expiration: some SwiftUI.View { + Group { + switch store.expiration { + case .none: + Color.clear + case let .window(seconds): + let value = formatTime(seconds: seconds) + Text("Valid for **\(value) after approval**") + case .atTime: + if let seconds = store.secondsToExpiration { + if seconds > 0 { + let value = formatTime(seconds: seconds) + Text("Valid for the next **\(value)**") + } else { + Text("Invalid!") + } + } + } + } + .textStyle(.body2Regular) + .foregroundStyle(.app.account4pink) + .padding(.horizontal, .medium1) + .frame(minHeight: .huge2) + } + + private var slider: some SwiftUI.View { + ApprovalSlider( + title: "Slide to sign and return", + resetDate: store.sliderResetDate + ) {} + .controlState(store.sliderControlState) + .padding(.horizontal, .medium2) + } + } +} + +private extension PreAuthorizationReview.View { + /// Given an amount of seconds, returns a formatted String using the corresponding unit (days/hours/minutes/seconds). + /// A few examples on how should it look for each of them: + /// - `8 days` / `1 day` + /// - `23:21 hours` / `1:24 hour` + /// - `56:02 minutes` / `1:23 minute` + /// - `34 seconds` / `1 second` + func formatTime(seconds: Int) -> String { + let minutes = seconds / 60 + let hours = minutes / 60 + let days = hours / 24 + if days > 0 { + return days == 1 ? "1 day" : "\(days) days" + } else if hours > 0 { + let remainingMinutes = minutes % 60 + let formatted = String(format: "%d:%02d", hours, remainingMinutes) + return hours == 1 ? "\(formatted) hour" : "\(formatted) hours" + } else if minutes > 0 { + let remainingSeconds = seconds % 60 + let formatted = String(format: "%d:%02d", minutes, remainingSeconds) + return minutes == 1 ? "\(formatted) minute" : "\(formatted) minutes" + } else { + return seconds == 1 ? "1 second" : "\(seconds) seconds" + } } } -extension PreAuthorizationReview.State { +private extension PreAuthorizationReview.State { var showTransferLine: Bool { true } + + var controlState: ControlState { + // If is loading transaction show loading + .enabled + } + + var sliderControlState: ControlState { + isExpired ? .disabled : controlState + } } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index e0f6f988ed..a249faed5a 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -7,6 +7,11 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { struct State: Sendable, Hashable { var dappName: String? = "Collabo.Fi" var displayMode: Common.DisplayMode = .detailed + var sliderResetDate: Date = .now // TODO: reset when it corresponds + + var expiration: Expiration? + var secondsToExpiration: Int? // Only valid when expiration == .atTime + init() {} } @@ -18,6 +23,12 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { case copyRawTransactionButtonTapped } + enum InternalAction: Sendable, Equatable { + case updateSecondsToExpiration(Date) + } + + @Dependency(\.continuousClock) var clock + var body: some ReducerOf { Reduce(core) } @@ -25,7 +36,10 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { func reduce(into state: inout State, viewAction: ViewAction) -> Effect { switch viewAction { case .appeared: - return .none + let time = Date().addingTimeInterval(14) + state.expiration = .atTime(time) + return startTimer(expirationDate: time) + case .toggleDisplayModeButtonTapped: switch state.displayMode { case .detailed: @@ -34,10 +48,45 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { state.displayMode = .detailed } return .none + case .copyRawTransactionButtonTapped: return .none } } + + func reduce(into state: inout State, internalAction: InternalAction) -> Effect { + switch internalAction { + case let .updateSecondsToExpiration(expiration): + state.secondsToExpiration = Int(expiration.timeIntervalSinceNow) + return .none + } + } +} + +private extension PreAuthorizationReview { + enum CancellableId: Hashable { + case expirationTimer + } + + func startTimer(expirationDate: Date) -> Effect { + .run { send in + for await _ in self.clock.timer(interval: .seconds(1)) { + await send(.internal(.updateSecondsToExpiration(expirationDate))) + } + } + .cancellable(id: CancellableId.expirationTimer, cancelInFlight: true) + } +} + +extension PreAuthorizationReview.State { + var isExpired: Bool { + switch expiration { + case let .atTime(date): + date <= Date.now + case .window, .none: + false + } + } } extension PreAuthorizationReview.State { @@ -69,3 +118,9 @@ extension PreAuthorizationReview.State { """ } } + +// MARK: - Expiration +enum Expiration: Sendable, Hashable { + case atTime(Date) + case window(Int) +} From 6cdea3c2034d743477053c01fe48267d40283b09 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 21 Oct 2024 12:35:41 -0300 Subject: [PATCH 08/63] WIP --- .../PreAuthorizationReview/PreAuthorizationReview.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index a249faed5a..74f1c60be7 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -28,6 +28,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { } @Dependency(\.continuousClock) var clock + @Dependency(\.pasteboardClient) var pasteboardClient var body: some ReducerOf { Reduce(core) @@ -38,6 +39,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { case .appeared: let time = Date().addingTimeInterval(14) state.expiration = .atTime(time) + state.secondsToExpiration = Int(time.timeIntervalSinceNow) return startTimer(expirationDate: time) case .toggleDisplayModeButtonTapped: @@ -50,6 +52,11 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { return .none case .copyRawTransactionButtonTapped: + guard case let .raw(manifest) = state.displayMode else { + assertionFailure("Copy raw manifest button should only be visible in raw transaction mode") + return .none + } + pasteboardClient.copyString(manifest) return .none } } From 4dd4d35194e1331f04c77cf7b15c3df6ce428cd5 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 21 Oct 2024 15:04:29 -0300 Subject: [PATCH 09/63] move more stuff to common --- RadixWallet.xcodeproj/project.pbxproj | 66 +++++++------ .../InteractionReviewCommon/DisplayMode.swift | 0 .../InteractionReviewCommon/HeaderView.swift | 0 .../InteractionReviewCommon/HeadingView.swift | 0 .../InteractionReviewCommon+Extra.swift | 0 .../InteractionReviewCommon.swift} | 0 .../RawTransactionView.swift | 0 .../Sections/Accounts/Accounts+View.swift} | 23 +++-- .../Sections/Accounts/Accounts.swift | 95 +++++++++++++++++++ .../Sections/Proofs/Proofs+View.swift} | 8 +- .../Sections/Proofs/Proofs.swift | 39 ++++++++ .../Sections/Sections.swift | 21 ++++ .../TransferLineView.swift | 0 .../PreAuthorizationReview.swift | 23 +++-- .../TransactionReview+Sections.swift | 52 ++++------ .../TransactionReview+View.swift | 6 +- .../TransactionReview.swift | 27 +++--- .../TransactionReviewAccount.swift | 91 ------------------ .../TransactionReviewProofs.swift | 33 ------- 19 files changed, 256 insertions(+), 228 deletions(-) rename RadixWallet/Features/{PreAuthorizationReview => }/InteractionReviewCommon/DisplayMode.swift (100%) rename RadixWallet/Features/{PreAuthorizationReview => }/InteractionReviewCommon/HeaderView.swift (100%) rename RadixWallet/Features/{PreAuthorizationReview => }/InteractionReviewCommon/HeadingView.swift (100%) rename RadixWallet/Features/{PreAuthorizationReview => }/InteractionReviewCommon/InteractionReviewCommon+Extra.swift (100%) rename RadixWallet/Features/{PreAuthorizationReview/InteractionReviewCommon/InteractionReview.swift => InteractionReviewCommon/InteractionReviewCommon.swift} (100%) rename RadixWallet/Features/{PreAuthorizationReview => }/InteractionReviewCommon/RawTransactionView.swift (100%) rename RadixWallet/Features/{TransactionReviewFeature/TransactionReviewAccount/TransactionReviewAccount+View.swift => InteractionReviewCommon/Sections/Accounts/Accounts+View.swift} (87%) create mode 100644 RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts.swift rename RadixWallet/Features/{TransactionReviewFeature/TransactionReviewProofs/TransactionReviewProofs+View.swift => InteractionReviewCommon/Sections/Proofs/Proofs+View.swift} (77%) create mode 100644 RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift create mode 100644 RadixWallet/Features/InteractionReviewCommon/Sections/Sections.swift rename RadixWallet/Features/{PreAuthorizationReview => }/InteractionReviewCommon/TransferLineView.swift (100%) delete mode 100644 RadixWallet/Features/TransactionReviewFeature/TransactionReviewAccount/TransactionReviewAccount.swift delete mode 100644 RadixWallet/Features/TransactionReviewFeature/TransactionReviewProofs/TransactionReviewProofs.swift diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index 4e3e8c8fae..b3c9b87454 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -127,12 +127,12 @@ 48CFC2882ADC10D900E77A5C /* MinimumPercentageStepper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCDB2ADC10D800E77A5C /* MinimumPercentageStepper.swift */; }; 48CFC2892ADC10D900E77A5C /* TransactionReviewGuarantees+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCDC2ADC10D800E77A5C /* TransactionReviewGuarantees+View.swift */; }; 48CFC28A2ADC10D900E77A5C /* TransactionReviewGuarantees.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCDD2ADC10D800E77A5C /* TransactionReviewGuarantees.swift */; }; - 48CFC28B2ADC10D900E77A5C /* TransactionReviewProofs+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCDF2ADC10D800E77A5C /* TransactionReviewProofs+View.swift */; }; - 48CFC28C2ADC10D900E77A5C /* TransactionReviewProofs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCE02ADC10D800E77A5C /* TransactionReviewProofs.swift */; }; + 48CFC28B2ADC10D900E77A5C /* Proofs+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCDF2ADC10D800E77A5C /* Proofs+View.swift */; }; + 48CFC28C2ADC10D900E77A5C /* Proofs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCE02ADC10D800E77A5C /* Proofs.swift */; }; 48CFC28D2ADC10D900E77A5C /* TransactionReviewRawTransaction+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCE22ADC10D800E77A5C /* TransactionReviewRawTransaction+View.swift */; }; 48CFC28E2ADC10D900E77A5C /* TransactionReviewRawTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCE32ADC10D800E77A5C /* TransactionReviewRawTransaction.swift */; }; - 48CFC28F2ADC10D900E77A5C /* TransactionReviewAccount+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCE52ADC10D800E77A5C /* TransactionReviewAccount+View.swift */; }; - 48CFC2902ADC10D900E77A5C /* TransactionReviewAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCE62ADC10D800E77A5C /* TransactionReviewAccount.swift */; }; + 48CFC28F2ADC10D900E77A5C /* Accounts+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCE52ADC10D800E77A5C /* Accounts+View.swift */; }; + 48CFC2902ADC10D900E77A5C /* Accounts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCE62ADC10D800E77A5C /* Accounts.swift */; }; 48CFC2912ADC10D900E77A5C /* TransactionReviewNetworkFee+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCE82ADC10D800E77A5C /* TransactionReviewNetworkFee+View.swift */; }; 48CFC2922ADC10D900E77A5C /* TransactionReviewNetworkFee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCE92ADC10D800E77A5C /* TransactionReviewNetworkFee.swift */; }; 48CFC2932ADC10D900E77A5C /* AdvancedFeesCustomization+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCEB2ADC10D800E77A5C /* AdvancedFeesCustomization+View.swift */; }; @@ -722,6 +722,7 @@ 5B272DD92C36E93100B74F1F /* AppEventsClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B272DD82C36E93100B74F1F /* AppEventsClient+Live.swift */; }; 5B272DDB2C36E9D300B74F1F /* AppEventsClient+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B272DDA2C36E9D300B74F1F /* AppEventsClient+Test.swift */; }; 5B27FBD92CC67655002975BE /* HeadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBD82CC67655002975BE /* HeadingView.swift */; }; + 5B27FBE02CC6CCBE002975BE /* Sections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBDF2CC6CCBE002975BE /* Sections.swift */; }; 5B2A45022BD6680400AEC8AD /* ContactSupportClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */; }; 5B2A45042BD6689100AEC8AD /* ContactSupportClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */; }; 5B3C48A92C7E190C00DB160D /* AssetRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B3C48A82C7E190C00DB160D /* AssetRow.swift */; }; @@ -745,7 +746,7 @@ 5B4A1ABB2CBFEBB000679EE6 /* ProofOfOwnership.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AB82CBFEBB000679EE6 /* ProofOfOwnership.swift */; }; 5B4A1ABF2CC00FB800679EE6 /* PreAuthorizationReview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */; }; 5B4A1AC02CC00FB800679EE6 /* PreAuthorizationReview+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */; }; - 5B4A1AC42CC0125700679EE6 /* InteractionReview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */; }; + 5B4A1AC42CC0125700679EE6 /* InteractionReviewCommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AC32CC0123300679EE6 /* InteractionReviewCommon.swift */; }; 5B4A1AC62CC0151300679EE6 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */; }; 5B4E1D132CB421EB002FAC2E /* DepositStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4E1D122CB421E3002FAC2E /* DepositStatus.swift */; }; 5B4E1D1F2CB7FE8E002FAC2E /* Sargon in Frameworks */ = {isa = PBXBuildFile; productRef = 5B4E1D1E2CB7FE8E002FAC2E /* Sargon */; }; @@ -1387,12 +1388,12 @@ 48CFBCDB2ADC10D800E77A5C /* MinimumPercentageStepper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimumPercentageStepper.swift; sourceTree = ""; }; 48CFBCDC2ADC10D800E77A5C /* TransactionReviewGuarantees+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TransactionReviewGuarantees+View.swift"; sourceTree = ""; }; 48CFBCDD2ADC10D800E77A5C /* TransactionReviewGuarantees.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionReviewGuarantees.swift; sourceTree = ""; }; - 48CFBCDF2ADC10D800E77A5C /* TransactionReviewProofs+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TransactionReviewProofs+View.swift"; sourceTree = ""; }; - 48CFBCE02ADC10D800E77A5C /* TransactionReviewProofs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionReviewProofs.swift; sourceTree = ""; }; + 48CFBCDF2ADC10D800E77A5C /* Proofs+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Proofs+View.swift"; sourceTree = ""; }; + 48CFBCE02ADC10D800E77A5C /* Proofs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Proofs.swift; sourceTree = ""; }; 48CFBCE22ADC10D800E77A5C /* TransactionReviewRawTransaction+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TransactionReviewRawTransaction+View.swift"; sourceTree = ""; }; 48CFBCE32ADC10D800E77A5C /* TransactionReviewRawTransaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionReviewRawTransaction.swift; sourceTree = ""; }; - 48CFBCE52ADC10D800E77A5C /* TransactionReviewAccount+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TransactionReviewAccount+View.swift"; sourceTree = ""; }; - 48CFBCE62ADC10D800E77A5C /* TransactionReviewAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionReviewAccount.swift; sourceTree = ""; }; + 48CFBCE52ADC10D800E77A5C /* Accounts+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Accounts+View.swift"; sourceTree = ""; }; + 48CFBCE62ADC10D800E77A5C /* Accounts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Accounts.swift; sourceTree = ""; }; 48CFBCE82ADC10D800E77A5C /* TransactionReviewNetworkFee+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TransactionReviewNetworkFee+View.swift"; sourceTree = ""; }; 48CFBCE92ADC10D800E77A5C /* TransactionReviewNetworkFee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionReviewNetworkFee.swift; sourceTree = ""; }; 48CFBCEB2ADC10D800E77A5C /* AdvancedFeesCustomization+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AdvancedFeesCustomization+View.swift"; sourceTree = ""; }; @@ -1951,6 +1952,7 @@ 5B272DD82C36E93100B74F1F /* AppEventsClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppEventsClient+Live.swift"; sourceTree = ""; }; 5B272DDA2C36E9D300B74F1F /* AppEventsClient+Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppEventsClient+Test.swift"; sourceTree = ""; }; 5B27FBD82CC67655002975BE /* HeadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadingView.swift; sourceTree = ""; }; + 5B27FBDF2CC6CCBE002975BE /* Sections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sections.swift; sourceTree = ""; }; 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactSupportClient.swift; sourceTree = ""; }; 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactSupportClient+Live.swift"; sourceTree = ""; }; 5B3C48A82C7E190C00DB160D /* AssetRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetRow.swift; sourceTree = ""; }; @@ -1973,7 +1975,7 @@ 5B4A1AB92CBFEBB000679EE6 /* ProofOfOwnership+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProofOfOwnership+View.swift"; sourceTree = ""; }; 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreAuthorizationReview.swift; sourceTree = ""; }; 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationReview+View.swift"; sourceTree = ""; }; - 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractionReview.swift; sourceTree = ""; }; + 5B4A1AC32CC0123300679EE6 /* InteractionReviewCommon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractionReviewCommon.swift; sourceTree = ""; }; 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = ""; }; 5B4E1D122CB421E3002FAC2E /* DepositStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepositStatus.swift; sourceTree = ""; }; 5B526ADA2C876E7C00AF8B72 /* AccountLockerClaimDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountLockerClaimDetails.swift; sourceTree = ""; }; @@ -2718,6 +2720,7 @@ 48CFBCBF2ADC10D800E77A5C /* P2PLinksFeature */, 48CFBCC62ADC10D800E77A5C /* AppFeature */, 48CFBCD02ADC10D800E77A5C /* TransactionReviewFeature */, + 5B4A1AC22CC0120600679EE6 /* InteractionReviewCommon */, 5B4A1ABC2CC00F7F00679EE6 /* PreAuthorizationReview */, 48CFBCF92ADC10D800E77A5C /* DappsAndPersonas */, 48CFBD0E2ADC10D800E77A5C /* HomeFeature */, @@ -3004,9 +3007,7 @@ 48CFBCD12ADC10D800E77A5C /* SelectFeePayer */, 48CFBCD52ADC10D800E77A5C /* SubmitTransaction */, 48CFBCD82ADC10D800E77A5C /* TransactionReviewGuarantees */, - 48CFBCDE2ADC10D800E77A5C /* TransactionReviewProofs */, 48CFBCE12ADC10D800E77A5C /* TransactionReviewRawTransaction */, - 48CFBCE42ADC10D800E77A5C /* TransactionReviewAccount */, 48CFBCE72ADC10D800E77A5C /* TransactionReviewNetworkFee */, 48CFBCEA2ADC10D800E77A5C /* CustomizeFees */, 48CFBCF22ADC10D800E77A5C /* TransactionReviewDapps */, @@ -3053,13 +3054,13 @@ path = MinimumPercentageStepper; sourceTree = ""; }; - 48CFBCDE2ADC10D800E77A5C /* TransactionReviewProofs */ = { + 48CFBCDE2ADC10D800E77A5C /* Proofs */ = { isa = PBXGroup; children = ( - 48CFBCDF2ADC10D800E77A5C /* TransactionReviewProofs+View.swift */, - 48CFBCE02ADC10D800E77A5C /* TransactionReviewProofs.swift */, + 48CFBCE02ADC10D800E77A5C /* Proofs.swift */, + 48CFBCDF2ADC10D800E77A5C /* Proofs+View.swift */, ); - path = TransactionReviewProofs; + path = Proofs; sourceTree = ""; }; 48CFBCE12ADC10D800E77A5C /* TransactionReviewRawTransaction */ = { @@ -3071,13 +3072,13 @@ path = TransactionReviewRawTransaction; sourceTree = ""; }; - 48CFBCE42ADC10D800E77A5C /* TransactionReviewAccount */ = { + 48CFBCE42ADC10D800E77A5C /* Accounts */ = { isa = PBXGroup; children = ( - 48CFBCE52ADC10D800E77A5C /* TransactionReviewAccount+View.swift */, - 48CFBCE62ADC10D800E77A5C /* TransactionReviewAccount.swift */, + 48CFBCE62ADC10D800E77A5C /* Accounts.swift */, + 48CFBCE52ADC10D800E77A5C /* Accounts+View.swift */, ); - path = TransactionReviewAccount; + path = Accounts; sourceTree = ""; }; 48CFBCE72ADC10D800E77A5C /* TransactionReviewNetworkFee */ = { @@ -5511,6 +5512,16 @@ path = AppEventsClient; sourceTree = ""; }; + 5B27FBDE2CC6CCA6002975BE /* Sections */ = { + isa = PBXGroup; + children = ( + 5B27FBDF2CC6CCBE002975BE /* Sections.swift */, + 48CFBCE42ADC10D800E77A5C /* Accounts */, + 48CFBCDE2ADC10D800E77A5C /* Proofs */, + ); + path = Sections; + sourceTree = ""; + }; 5B2A45002BD667FB00AEC8AD /* ContactSupportClient */ = { isa = PBXGroup; children = ( @@ -5572,7 +5583,6 @@ 5B4A1ABC2CC00F7F00679EE6 /* PreAuthorizationReview */ = { isa = PBXGroup; children = ( - 5B4A1AC22CC0120600679EE6 /* InteractionReviewCommon */, 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */, 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */, ); @@ -5582,13 +5592,14 @@ 5B4A1AC22CC0120600679EE6 /* InteractionReviewCommon */ = { isa = PBXGroup; children = ( - 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */, + 5B4A1AC32CC0123300679EE6 /* InteractionReviewCommon.swift */, 5B03E3D22CC141C200E10A64 /* InteractionReviewCommon+Extra.swift */, 5B27FBD82CC67655002975BE /* HeadingView.swift */, 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */, 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */, 5B03E3CE2CC1222D00E10A64 /* DisplayMode.swift */, 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */, + 5B27FBDE2CC6CCA6002975BE /* Sections */, ); path = InteractionReviewCommon; sourceTree = ""; @@ -7247,6 +7258,7 @@ A4ECE2722BEEAFFC00468BF6 /* SecurityCenterClient+Interface.swift in Sources */, 48CFC2A62ADC10D900E77A5C /* PersonaDetails.swift in Sources */, A40815C12C7E0D08005E65B9 /* NonFungibleIdsCollection.swift in Sources */, + 5B27FBE02CC6CCBE002975BE /* Sections.swift in Sources */, 83D663B02B271D0100D1AB9E /* TruncationMask.swift in Sources */, 48CFC3462ADC10D900E77A5C /* Completion.swift in Sources */, A40816002C7E0D08005E65B9 /* StateAccountLockersTouchedAtResponse.swift in Sources */, @@ -7317,7 +7329,7 @@ 48CFC27A2ADC10D900E77A5C /* App+View.swift in Sources */, A40815E72C7E0D08005E65B9 /* ProgrammaticScryptoSborValueU128.swift in Sources */, E7AE2D0E2C07359500830BAA /* FullScreenOverlayCoordinator+Reducer.swift in Sources */, - 5B4A1AC42CC0125700679EE6 /* InteractionReview.swift in Sources */, + 5B4A1AC42CC0125700679EE6 /* InteractionReviewCommon.swift in Sources */, 48CFC3ED2ADC10D900E77A5C /* DataChannelMessage+Codable.swift in Sources */, A408163B2C7E0D08005E65B9 /* TransactionAccountDepositPreValidationAuthorizedDepositorBadge.swift in Sources */, 48CFC5DA2ADC10DA00E77A5C /* PresentationDetentIntrinsicHeight.swift in Sources */, @@ -7400,7 +7412,7 @@ 48CFC4642ADC10DA00E77A5C /* OverlayWindowClient+Interface.swift in Sources */, 48CFC58C2ADC10DA00E77A5C /* OnboardingClient+Live.swift in Sources */, 48CFC4872ADC10DA00E77A5C /* OnLedgerEntitiesClient+Test.swift in Sources */, - 48CFC28B2ADC10D900E77A5C /* TransactionReviewProofs+View.swift in Sources */, + 48CFC28B2ADC10D900E77A5C /* Proofs+View.swift in Sources */, 8397D82D2B46ACB50016365A /* StakeUnitList.swift in Sources */, 48CFC44C2ADC10DA00E77A5C /* MnemonicClient+Test.swift in Sources */, 48CFC4192ADC10DA00E77A5C /* Tuple+Extra.swift in Sources */, @@ -7887,7 +7899,7 @@ E7D8D8C22C35349F00032417 /* AssetsView+Selection.swift in Sources */, A462B5B92B90C57400C26D20 /* ResourceBalanceButton.swift in Sources */, A47809082BDBDB4C006B68C0 /* RadixDateFormatter.swift in Sources */, - 48CFC28F2ADC10D900E77A5C /* TransactionReviewAccount+View.swift in Sources */, + 48CFC28F2ADC10D900E77A5C /* Accounts+View.swift in Sources */, 48CFC33D2ADC10D900E77A5C /* DappInteractionCoordinator.swift in Sources */, A40816222C7E0D08005E65B9 /* StateKeyValueStoreDataRequestKeyItem.swift in Sources */, 48CFC4502ADC10DA00E77A5C /* PersonasClient+Live.swift in Sources */, @@ -8074,7 +8086,7 @@ A4A96BB82C7743B200E19CD5 /* InfoButton.swift in Sources */, 4813B0032BCA4FD60046BCAD /* Stage1MigrateToSargon+Persona.swift in Sources */, 48CFC4152ADC10DA00E77A5C /* PasteboardClient+Interface.swift in Sources */, - 48CFC2902ADC10D900E77A5C /* TransactionReviewAccount.swift in Sources */, + 48CFC2902ADC10D900E77A5C /* Accounts.swift in Sources */, 48CFC4632ADC10DA00E77A5C /* OverlayWindowClient+Test.swift in Sources */, E7AE2D102C07371C00830BAA /* FullScreenOverlayCoordinator+View.swift in Sources */, A462B5C32B95212600C26D20 /* TransactionHistoryFilters+View.swift in Sources */, @@ -8114,7 +8126,7 @@ A40815982C7E0D08005E65B9 /* MetadataNonFungibleLocalIdArrayValue.swift in Sources */, A4ECE27A2BEEB01800468BF6 /* CloudBackupClient+Live.swift in Sources */, 8338B9E52AFAB20700D1D8EA /* TransactionFee.swift in Sources */, - 48CFC28C2ADC10D900E77A5C /* TransactionReviewProofs.swift in Sources */, + 48CFC28C2ADC10D900E77A5C /* Proofs.swift in Sources */, 48CFC27F2ADC10D900E77A5C /* Overlay+View.swift in Sources */, 4884F3332BD83B4600A19B83 /* Stage1MigrateToSargon+OnLedgerSettings.swift in Sources */, 48AE39ED2B0CCA7600813CF3 /* RecoverWalletControlWithBDFSComplete.swift in Sources */, diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/DisplayMode.swift b/RadixWallet/Features/InteractionReviewCommon/DisplayMode.swift similarity index 100% rename from RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/DisplayMode.swift rename to RadixWallet/Features/InteractionReviewCommon/DisplayMode.swift diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/HeaderView.swift b/RadixWallet/Features/InteractionReviewCommon/HeaderView.swift similarity index 100% rename from RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/HeaderView.swift rename to RadixWallet/Features/InteractionReviewCommon/HeaderView.swift diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/HeadingView.swift b/RadixWallet/Features/InteractionReviewCommon/HeadingView.swift similarity index 100% rename from RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/HeadingView.swift rename to RadixWallet/Features/InteractionReviewCommon/HeadingView.swift diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/InteractionReviewCommon+Extra.swift b/RadixWallet/Features/InteractionReviewCommon/InteractionReviewCommon+Extra.swift similarity index 100% rename from RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/InteractionReviewCommon+Extra.swift rename to RadixWallet/Features/InteractionReviewCommon/InteractionReviewCommon+Extra.swift diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/InteractionReview.swift b/RadixWallet/Features/InteractionReviewCommon/InteractionReviewCommon.swift similarity index 100% rename from RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/InteractionReview.swift rename to RadixWallet/Features/InteractionReviewCommon/InteractionReviewCommon.swift diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/RawTransactionView.swift b/RadixWallet/Features/InteractionReviewCommon/RawTransactionView.swift similarity index 100% rename from RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/RawTransactionView.swift rename to RadixWallet/Features/InteractionReviewCommon/RawTransactionView.swift diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewAccount/TransactionReviewAccount+View.swift b/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts+View.swift similarity index 87% rename from RadixWallet/Features/TransactionReviewFeature/TransactionReviewAccount/TransactionReviewAccount+View.swift rename to RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts+View.swift index a43d9ed135..e0a35c30a7 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewAccount/TransactionReviewAccount+View.swift +++ b/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts+View.swift @@ -1,22 +1,22 @@ import ComposableArchitecture import SwiftUI -extension TransactionReviewAccounts.State { - var viewState: TransactionReviewAccounts.ViewState { +extension InteractionReviewCommon.Accounts.State { + var viewState: InteractionReviewCommon.Accounts.ViewState { .init(showCustomizeGuaranteesButton: enableCustomizeGuarantees) } } -extension TransactionReviewAccounts { +extension InteractionReviewCommon.Accounts { struct ViewState: Equatable { let showCustomizeGuaranteesButton: Bool } @MainActor struct View: SwiftUI.View { - private let store: StoreOf + private let store: StoreOf - init(store: StoreOf) { + init(store: StoreOf) { self.store = store } @@ -26,7 +26,7 @@ extension TransactionReviewAccounts { VStack(spacing: .small1) { ForEachStore( store.scope(state: \.accounts, action: \.child.account), - content: { TransactionReviewAccount.View(store: $0) } + content: { InteractionReviewCommon.Account.View(store: $0) } ) if viewStore.showCustomizeGuaranteesButton { @@ -45,14 +45,13 @@ extension TransactionReviewAccounts { } } -extension TransactionReviewAccount.State { - var viewState: TransactionReviewAccount.ViewState { +extension InteractionReviewCommon.Account.State { + var viewState: InteractionReviewCommon.Account.ViewState { .init(account: account, transfers: transfers.elements, showApprovedMark: account.isApproved, isDeposit: isDeposit) } } -// MARK: - TransactionReviewAccount.View -extension TransactionReviewAccount { +extension InteractionReviewCommon.Account { struct ViewState: Equatable { let account: TransactionReview.ReviewAccount let transfers: [TransactionReview.Transfer] // FIXME: GK use viewstate? @@ -62,9 +61,9 @@ extension TransactionReviewAccount { @MainActor struct View: SwiftUI.View { - private let store: StoreOf + private let store: StoreOf - init(store: StoreOf) { + init(store: StoreOf) { self.store = store } diff --git a/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts.swift b/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts.swift new file mode 100644 index 0000000000..1fb2448f7d --- /dev/null +++ b/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts.swift @@ -0,0 +1,95 @@ +import ComposableArchitecture +import SwiftUI + +// MARK: - InteractionReviewCommon.Accounts +extension InteractionReviewCommon { + struct Accounts: Sendable, FeatureReducer { + struct State: Sendable, Hashable { + init(accounts: IdentifiedArrayOf, enableCustomizeGuarantees: Bool) { + self.accounts = accounts + self.enableCustomizeGuarantees = enableCustomizeGuarantees + } + + var accounts: IdentifiedArrayOf + let enableCustomizeGuarantees: Bool + } + + enum ViewAction: Sendable, Equatable { + case customizeGuaranteesTapped + } + + @CasePathable + enum ChildAction: Sendable, Equatable { + case account(id: AccountAddress, action: InteractionReviewCommon.Account.Action) + } + + enum DelegateAction: Sendable, Equatable { + case showCustomizeGuarantees + case showAsset(ResourceBalance, OnLedgerEntity.NonFungibleToken?) + } + + init() {} + + var body: some ReducerOf { + Reduce(core) + .forEach(\.accounts, action: /Action.child .. ChildAction.account) { + InteractionReviewCommon.Account() + } + } + + func reduce(into state: inout State, viewAction: ViewAction) -> Effect { + switch viewAction { + case .customizeGuaranteesTapped: + .send(.delegate(.showCustomizeGuarantees)) + } + } + + func reduce(into state: inout State, childAction: ChildAction) -> Effect { + switch childAction { + case let .account(id: _, action: .delegate(.showAsset(transfer, token))): + .send(.delegate(.showAsset(transfer, token))) + case .account: + .none + } + } + } +} + +// MARK: - InteractionReviewCommon.Account +extension InteractionReviewCommon { + struct Account: Sendable, FeatureReducer { + struct State: Sendable, Identifiable, Hashable { + var id: AccountAddress { account.address } + let account: TransactionReview.ReviewAccount + var transfers: IdentifiedArrayOf + let isDeposit: Bool + + init(account: TransactionReview.ReviewAccount, transfers: IdentifiedArrayOf, isDeposit: Bool) { + self.account = account + self.transfers = transfers + self.isDeposit = isDeposit + } + } + + enum ViewAction: Sendable, Equatable { + case appeared + case transferTapped(ResourceBalance, OnLedgerEntity.NonFungibleToken?) + } + + enum DelegateAction: Sendable, Equatable { + case showAsset(ResourceBalance, OnLedgerEntity.NonFungibleToken?) + case showStakeClaim(OnLedgerEntitiesClient.StakeClaim) + } + + init() {} + + func reduce(into state: inout State, viewAction: ViewAction) -> Effect { + switch viewAction { + case .appeared: + .none + case let .transferTapped(transfer, token): + .send(.delegate(.showAsset(transfer, token))) + } + } + } +} diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewProofs/TransactionReviewProofs+View.swift b/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs+View.swift similarity index 77% rename from RadixWallet/Features/TransactionReviewFeature/TransactionReviewProofs/TransactionReviewProofs+View.swift rename to RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs+View.swift index 09d9f51a8d..b2aff3dc37 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewProofs/TransactionReviewProofs+View.swift +++ b/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs+View.swift @@ -1,13 +1,13 @@ import ComposableArchitecture import SwiftUI -// MARK: - TransactionReviewProofs.View -extension TransactionReviewProofs { +// MARK: - InteractionReviewProofs.View +extension InteractionReviewCommon.Proofs { @MainActor struct View: SwiftUI.View { - let store: StoreOf + let store: StoreOf - init(store: StoreOf) { + init(store: StoreOf) { self.store = store } diff --git a/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift b/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift new file mode 100644 index 0000000000..c68bc28ee2 --- /dev/null +++ b/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift @@ -0,0 +1,39 @@ +import ComposableArchitecture +import SwiftUI + +extension InteractionReviewCommon { + struct Proofs: Sendable, FeatureReducer { + struct State: Sendable, Hashable { + var proofs: IdentifiedArrayOf + + init(proofs: IdentifiedArrayOf) { + self.proofs = proofs + } + } + + enum ViewAction: Sendable, Equatable { + case infoTapped + case proofTapped(ProofEntity) + } + + enum DelegateAction: Sendable, Equatable { + case showAsset(ProofEntity) + } + + init() {} + + func reduce(into state: inout State, viewAction: ViewAction) -> Effect { + switch viewAction { + case .infoTapped: + .none + case let .proofTapped(proof): + .send(.delegate(.showAsset(proof))) + } + } + } + + struct ProofEntity: Sendable, Identifiable, Hashable { + var id: ResourceBalance { resourceBalance } + let resourceBalance: ResourceBalance + } +} diff --git a/RadixWallet/Features/InteractionReviewCommon/Sections/Sections.swift b/RadixWallet/Features/InteractionReviewCommon/Sections/Sections.swift new file mode 100644 index 0000000000..d2dba842c4 --- /dev/null +++ b/RadixWallet/Features/InteractionReviewCommon/Sections/Sections.swift @@ -0,0 +1,21 @@ +import Foundation + +extension InteractionReviewCommon { + struct Sections: Sendable, Hashable { + var withdrawals: Accounts.State? = nil + var dAppsUsed: TransactionReviewDappsUsed.State? = nil + var deposits: Accounts.State? = nil + + var contributingToPools: TransactionReviewPools.State? = nil + var redeemingFromPools: TransactionReviewPools.State? = nil + + var stakingToValidators: TransactionReview.ValidatorsState? = nil + var unstakingFromValidators: TransactionReview.ValidatorsState? = nil + var claimingFromValidators: TransactionReview.ValidatorsState? = nil + + var accountDepositSetting: TransactionReview.DepositSettingState? = nil + var accountDepositExceptions: TransactionReview.DepositExceptionsState? = nil + + var proofs: Proofs.State? = nil + } +} diff --git a/RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/TransferLineView.swift b/RadixWallet/Features/InteractionReviewCommon/TransferLineView.swift similarity index 100% rename from RadixWallet/Features/PreAuthorizationReview/InteractionReviewCommon/TransferLineView.swift rename to RadixWallet/Features/InteractionReviewCommon/TransferLineView.swift diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 74f1c60be7..ef4cb89f58 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -10,7 +10,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { var sliderResetDate: Date = .now // TODO: reset when it corresponds var expiration: Expiration? - var secondsToExpiration: Int? // Only valid when expiration == .atTime + var secondsToExpiration: Int? init() {} } @@ -37,7 +37,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { func reduce(into state: inout State, viewAction: ViewAction) -> Effect { switch viewAction { case .appeared: - let time = Date().addingTimeInterval(14) + let time = Date().addingTimeInterval(90) state.expiration = .atTime(time) state.secondsToExpiration = Int(time.timeIntervalSinceNow) return startTimer(expirationDate: time) @@ -52,7 +52,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { return .none case .copyRawTransactionButtonTapped: - guard case let .raw(manifest) = state.displayMode else { + guard let manifest = state.displayMode.rawTransaction else { assertionFailure("Copy raw manifest button should only be visible in raw transaction mode") return .none } @@ -71,10 +71,6 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { } private extension PreAuthorizationReview { - enum CancellableId: Hashable { - case expirationTimer - } - func startTimer(expirationDate: Date) -> Effect { .run { send in for await _ in self.clock.timer(interval: .seconds(1)) { @@ -85,6 +81,18 @@ private extension PreAuthorizationReview { } } +private extension PreAuthorizationReview { + enum CancellableId: Hashable { + case expirationTimer + } + + struct ReviewedPreAuthorization: Sendable, Hashable { + let manifest: TransactionManifest + + // TODO: Fill required info once we have Sargon ready + } +} + extension PreAuthorizationReview.State { var isExpired: Bool { switch expiration { @@ -128,6 +136,7 @@ extension PreAuthorizationReview.State { // MARK: - Expiration enum Expiration: Sendable, Hashable { + // TODO: Replace with Sargon model case atTime(Date) case window(Int) } diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift index 340a2cde2a..c76769dd51 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift @@ -7,25 +7,7 @@ extension TransactionReview { typealias ResourcesInfo = [ResourceAddress: ResourceInfo] typealias ResourceAssociatedDapps = [ResourceAddress: OnLedgerEntity.Metadata] - struct Sections: Sendable, Hashable { - var withdrawals: TransactionReviewAccounts.State? = nil - var dAppsUsed: TransactionReviewDappsUsed.State? = nil - var deposits: TransactionReviewAccounts.State? = nil - - var contributingToPools: TransactionReviewPools.State? = nil - var redeemingFromPools: TransactionReviewPools.State? = nil - - var stakingToValidators: ValidatorsState? = nil - var unstakingFromValidators: ValidatorsState? = nil - var claimingFromValidators: ValidatorsState? = nil - - var accountDepositSetting: DepositSettingState? = nil - var accountDepositExceptions: DepositExceptionsState? = nil - - var proofs: TransactionReviewProofs.State? = nil - } - - func sections(for summary: ExecutionSummary, networkID: NetworkID) async throws -> Sections? { + func sections(for summary: ExecutionSummary, networkID: NetworkID) async throws -> Common.Sections? { let allWithdrawAddresses = summary.withdrawals.values.flatMap { $0 }.map(\.resourceAddress) let allDepositAddresses = summary.deposits.values.flatMap { $0 }.map(\.resourceAddress) @@ -96,9 +78,9 @@ extension TransactionReview { networkID: networkID ) - let proofs: TransactionReviewProofs.State? = try await exctractProofs(summary.presentedProofs) + let proofs = try await exctractProofs(summary.presentedProofs) - return Sections( + return Common.Sections( withdrawals: withdrawals, dAppsUsed: dAppsUsed, deposits: deposits, @@ -138,7 +120,7 @@ extension TransactionReview { networkID: networkID ) - return Sections( + return Common.Sections( withdrawals: withdrawals, deposits: deposits, contributingToPools: pools @@ -179,7 +161,7 @@ extension TransactionReview { networkID: networkID ) - return Sections( + return Common.Sections( withdrawals: withdrawals, deposits: deposits, redeemingFromPools: pools @@ -207,7 +189,7 @@ extension TransactionReview { networkID: networkID ) - return Sections( + return Common.Sections( withdrawals: withdrawals, deposits: deposits, stakingToValidators: stakingToValidators @@ -235,7 +217,7 @@ extension TransactionReview { networkID: networkID ) - return Sections( + return Common.Sections( withdrawals: withdrawals, deposits: deposits, unstakingFromValidators: unstakingFromValidators @@ -261,7 +243,7 @@ extension TransactionReview { networkID: networkID ) - return Sections( + return Common.Sections( withdrawals: withdrawals, deposits: deposits, claimingFromValidators: claimingFromValidators @@ -296,7 +278,7 @@ extension TransactionReview { authorizedDepositorsRemoved: authorizedDepositorsRemoved ) - return Sections( + return Common.Sections( accountDepositSetting: accountDepositSetting, accountDepositExceptions: accountDepositExceptions ) @@ -352,7 +334,7 @@ extension TransactionReview { return DappEntity(id: dAppDefinitionAddress, metadata: metadata) } - private func exctractProofs(_ accountProofs: [ResourceSpecifier]) async throws -> TransactionReviewProofs.State? { + private func exctractProofs(_ accountProofs: [ResourceSpecifier]) async throws -> Common.Proofs.State? { let proofs = try await accountProofs .uniqued() .asyncMap(extractResourceBalanceInfo) @@ -361,7 +343,7 @@ extension TransactionReview { guard !proofs.isEmpty else { return nil } - return TransactionReviewProofs.State(proofs: proofs.asIdentified()) + return Common.Proofs.State(proofs: proofs.asIdentified()) } private func extractResourceBalanceInfo(specifier: ResourceSpecifier) async throws -> [(ResourceAddress, ResourceBalance.Details)] { @@ -385,8 +367,8 @@ extension TransactionReview { } } - private func extractProofInfo(resourceAddress: ResourceAddress, details: ResourceBalance.Details) async throws -> ProofEntity { - try await ProofEntity( + private func extractProofInfo(resourceAddress: ResourceAddress, details: ResourceBalance.Details) async throws -> Common.ProofEntity { + try await Common.ProofEntity( resourceBalance: ResourceBalance( resource: onLedgerEntitiesClient.getResource(resourceAddress, metadataKeys: .dappMetadataKeys), details: details @@ -401,7 +383,7 @@ extension TransactionReview { entities: ResourcesInfo = [:], resourceAssociatedDapps: ResourceAssociatedDapps? = nil, networkID: NetworkID - ) async throws -> TransactionReviewAccounts.State? { + ) async throws -> Common.Accounts.State? { var withdrawals: [ReviewAccount: IdentifiedArrayOf] = [:] let userAccounts: [ReviewAccount] = try await extractUserAccounts(Array(accountWithdraws.keys)) @@ -426,7 +408,7 @@ extension TransactionReview { guard !withdrawals.isEmpty else { return nil } let withdrawalAccounts = withdrawals.map { - TransactionReviewAccount.State(account: $0.key, transfers: $0.value, isDeposit: false) + Common.Account.State(account: $0.key, transfers: $0.value, isDeposit: false) } .asIdentified() @@ -442,7 +424,7 @@ extension TransactionReview { entities: ResourcesInfo = [:], resourceAssociatedDapps: ResourceAssociatedDapps? = nil, networkID: NetworkID - ) async throws -> TransactionReviewAccounts.State? { + ) async throws -> Common.Accounts.State? { let userAccounts: [ReviewAccount] = try await extractUserAccounts(Array(accountDeposits.keys)) let defaultDepositGuarantee = await appPreferencesClient.getPreferences().transaction.defaultDepositGuarantee @@ -471,7 +453,7 @@ extension TransactionReview { let depositAccounts = deposits .filter { !$0.value.isEmpty } - .map { TransactionReviewAccount.State(account: $0.key, transfers: $0.value, isDeposit: true) } + .map { Common.Account.State(account: $0.key, transfers: $0.value, isDeposit: true) } .asIdentified() guard !depositAccounts.isEmpty else { return nil } diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index 3e66f3ea28..080d5bd33b 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -265,7 +265,7 @@ extension TransactionReview { IfLetStore(store.scope(state: \.withdrawals) { .child(.withdrawals($0)) }) { childStore in VStack(alignment: .leading, spacing: .small2) { Common.HeadingView.withdrawing - TransactionReviewAccounts.View(store: childStore) + Common.Accounts.View(store: childStore) } } } @@ -334,7 +334,7 @@ extension TransactionReview { IfLetStore(store.scope(state: \.deposits) { .child(.deposits($0)) }) { childStore in VStack(alignment: .leading, spacing: .small2) { Common.HeadingView.depositing - TransactionReviewAccounts.View(store: childStore) + Common.Accounts.View(store: childStore) } } } @@ -358,7 +358,7 @@ extension TransactionReview { private var proofsSection: some SwiftUI.View { let proofsStore = store.scope(state: \.proofs) { .child(.proofs($0)) } return IfLetStore(proofsStore) { childStore in - TransactionReviewProofs.View(store: childStore) + Common.Proofs.View(store: childStore) } } diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift index b48439010f..7ccb26a02c 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift @@ -22,11 +22,11 @@ struct TransactionReview: Sendable, FeatureReducer { var reviewedTransaction: ReviewedTransaction? = nil - var withdrawals: TransactionReviewAccounts.State? = nil + var withdrawals: Common.Accounts.State? = nil var dAppsUsed: TransactionReviewDappsUsed.State? = nil var contributingToPools: TransactionReviewPools.State? = nil var redeemingFromPools: TransactionReviewPools.State? = nil - var deposits: TransactionReviewAccounts.State? = nil + var deposits: Common.Accounts.State? = nil var stakingToValidators: ValidatorsState? = nil var unstakingFromValidators: ValidatorsState? = nil @@ -35,7 +35,7 @@ struct TransactionReview: Sendable, FeatureReducer { var accountDepositSetting: DepositSettingState? = nil var accountDepositExceptions: DepositExceptionsState? = nil - var proofs: TransactionReviewProofs.State? = nil + var proofs: Common.Proofs.State? = nil var networkFee: TransactionReviewNetworkFee.State? = nil let ephemeralNotaryPrivateKey: Curve25519.Signing.PrivateKey var canApproveTX: Bool = true @@ -111,18 +111,18 @@ struct TransactionReview: Sendable, FeatureReducer { } enum ChildAction: Sendable, Equatable { - case withdrawals(TransactionReviewAccounts.Action) - case deposits(TransactionReviewAccounts.Action) + case withdrawals(Common.Accounts.Action) + case deposits(Common.Accounts.Action) case dAppsUsed(TransactionReviewDappsUsed.Action) case contributingToPools(TransactionReviewPools.Action) case redeemingFromPools(TransactionReviewPools.Action) - case proofs(TransactionReviewProofs.Action) + case proofs(Common.Proofs.Action) case networkFee(TransactionReviewNetworkFee.Action) } enum InternalAction: Sendable, Equatable { case previewLoaded(TaskResult) - case updateSections(TransactionReview.Sections?) + case updateSections(Common.Sections?) case buildTransactionIntentResult(TaskResult) case notarizeResult(TaskResult) case determineFeePayerResult(TaskResult) @@ -219,7 +219,7 @@ struct TransactionReview: Sendable, FeatureReducer { TransactionReviewNetworkFee() } .ifLet(\.deposits, action: /Action.child .. ChildAction.deposits) { - TransactionReviewAccounts() + Common.Accounts() } .ifLet(\.dAppsUsed, action: /Action.child .. ChildAction.dAppsUsed) { TransactionReviewDappsUsed() @@ -231,10 +231,10 @@ struct TransactionReview: Sendable, FeatureReducer { TransactionReviewPools() } .ifLet(\.withdrawals, action: /Action.child .. ChildAction.withdrawals) { - TransactionReviewAccounts() + Common.Accounts() } .ifLet(\.proofs, action: /Action.child .. ChildAction.proofs) { - TransactionReviewProofs() + Common.Proofs() } .ifLet(destinationPath, action: /Action.destination) { Destination() @@ -596,7 +596,7 @@ extension AlertState { } } -extension Collection { +extension Collection { var customizableGuarantees: [TransactionReviewGuarantee.State] { flatMap { account in account.transfers.compactMap { .init(account: account.account, transfer: $0) } @@ -783,11 +783,6 @@ extension TransactionReview { // MARK: Useful types extension TransactionReview { - struct ProofEntity: Sendable, Identifiable, Hashable { - var id: ResourceBalance { resourceBalance } - let resourceBalance: ResourceBalance - } - struct DappEntity: Sendable, Identifiable, Hashable { let id: DappDefinitionAddress let metadata: OnLedgerEntity.Metadata diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewAccount/TransactionReviewAccount.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReviewAccount/TransactionReviewAccount.swift deleted file mode 100644 index eb15327b62..0000000000 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewAccount/TransactionReviewAccount.swift +++ /dev/null @@ -1,91 +0,0 @@ -import ComposableArchitecture -import SwiftUI - -// MARK: - TransactionReviewAccounts -struct TransactionReviewAccounts: Sendable, FeatureReducer { - struct State: Sendable, Hashable { - init(accounts: IdentifiedArrayOf, enableCustomizeGuarantees: Bool) { - self.accounts = accounts - self.enableCustomizeGuarantees = enableCustomizeGuarantees - } - - var accounts: IdentifiedArrayOf - let enableCustomizeGuarantees: Bool - } - - enum ViewAction: Sendable, Equatable { - case customizeGuaranteesTapped - } - - @CasePathable - enum ChildAction: Sendable, Equatable { - case account(id: AccountAddress, action: TransactionReviewAccount.Action) - } - - enum DelegateAction: Sendable, Equatable { - case showCustomizeGuarantees - case showAsset(ResourceBalance, OnLedgerEntity.NonFungibleToken?) - } - - init() {} - - var body: some ReducerOf { - Reduce(core) - .forEach(\.accounts, action: /Action.child .. ChildAction.account) { - TransactionReviewAccount() - } - } - - func reduce(into state: inout State, viewAction: ViewAction) -> Effect { - switch viewAction { - case .customizeGuaranteesTapped: - .send(.delegate(.showCustomizeGuarantees)) - } - } - - func reduce(into state: inout State, childAction: ChildAction) -> Effect { - switch childAction { - case let .account(id: _, action: .delegate(.showAsset(transfer, token))): - .send(.delegate(.showAsset(transfer, token))) - case .account: - .none - } - } -} - -// MARK: - TransactionReviewAccount -struct TransactionReviewAccount: Sendable, FeatureReducer { - struct State: Sendable, Identifiable, Hashable { - var id: AccountAddress { account.address } - let account: TransactionReview.ReviewAccount - var transfers: IdentifiedArrayOf - let isDeposit: Bool - - init(account: TransactionReview.ReviewAccount, transfers: IdentifiedArrayOf, isDeposit: Bool) { - self.account = account - self.transfers = transfers - self.isDeposit = isDeposit - } - } - - enum ViewAction: Sendable, Equatable { - case appeared - case transferTapped(ResourceBalance, OnLedgerEntity.NonFungibleToken?) - } - - enum DelegateAction: Sendable, Equatable { - case showAsset(ResourceBalance, OnLedgerEntity.NonFungibleToken?) - case showStakeClaim(OnLedgerEntitiesClient.StakeClaim) - } - - init() {} - - func reduce(into state: inout State, viewAction: ViewAction) -> Effect { - switch viewAction { - case .appeared: - .none - case let .transferTapped(transfer, token): - .send(.delegate(.showAsset(transfer, token))) - } - } -} diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewProofs/TransactionReviewProofs.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReviewProofs/TransactionReviewProofs.swift deleted file mode 100644 index 8baf0e6be3..0000000000 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewProofs/TransactionReviewProofs.swift +++ /dev/null @@ -1,33 +0,0 @@ -import ComposableArchitecture -import SwiftUI - -// MARK: - TransactionReviewProofs -struct TransactionReviewProofs: Sendable, FeatureReducer { - struct State: Sendable, Hashable { - var proofs: IdentifiedArrayOf - - init(proofs: IdentifiedArrayOf) { - self.proofs = proofs - } - } - - enum ViewAction: Sendable, Equatable { - case infoTapped - case proofTapped(TransactionReview.ProofEntity) - } - - enum DelegateAction: Sendable, Equatable { - case showAsset(TransactionReview.ProofEntity) - } - - init() {} - - func reduce(into state: inout State, viewAction: ViewAction) -> Effect { - switch viewAction { - case .infoTapped: - .none - case let .proofTapped(proof): - .send(.delegate(.showAsset(proof))) - } - } -} From 69af0a61ba9b2f61610fa44e7a5b6161218aaf90 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 21 Oct 2024 15:41:13 -0300 Subject: [PATCH 10/63] WIP --- .../PreAuthorizationReview+View.swift | 35 +++++++-- .../PreAuthorizationReview.swift | 72 +++++++++++++++++++ .../TransactionReview+Sections.swift | 3 +- 3 files changed, 105 insertions(+), 5 deletions(-) diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index 4623e14e6e..d50ce7078b 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -103,12 +103,10 @@ extension PreAuthorizationReview { private var details: some SwiftUI.View { VStack(alignment: .leading, spacing: .medium1) { - Common.HeadingView.withdrawing + withdrawals VStack(alignment: .leading, spacing: .medium1) { - Common.HeadingView.contributingToPools - - Common.HeadingView.redeemingFromPools + deposits } .frame(maxWidth: .infinity, alignment: .leading) // necessary? .background(alignment: .trailing) { @@ -116,6 +114,8 @@ extension PreAuthorizationReview { Common.TransferLineView() } } + + proofs } .padding(.top, .large2 + .small3) .padding(.horizontal, .small1) @@ -129,6 +129,33 @@ extension PreAuthorizationReview { } } + @ViewBuilder + private var withdrawals: some SwiftUI.View { + if let childStore = store.scope(state: \.withdrawals, action: \.child.withdrawals) { + VStack(alignment: .leading, spacing: .small2) { + Common.HeadingView.withdrawing + Common.Accounts.View(store: childStore) + } + } + } + + @ViewBuilder + private var deposits: some SwiftUI.View { + if let childStore = store.scope(state: \.deposits, action: \.child.deposits) { + VStack(alignment: .leading, spacing: .small2) { + Common.HeadingView.depositing + Common.Accounts.View(store: childStore) + } + } + } + + @ViewBuilder + private var proofs: some SwiftUI.View { + if let childStore = store.scope(state: \.proofs, action: \.child.proofs) { + Common.Proofs.View(store: childStore) + } + } + private var feesInformation: some SwiftUI.View { HStack(spacing: .zero) { VStack(alignment: .leading, spacing: .zero) { diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index ef4cb89f58..8c6e44179d 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -12,6 +12,11 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { var expiration: Expiration? var secondsToExpiration: Int? + // Sections + var withdrawals: Common.Accounts.State? = nil + var deposits: Common.Accounts.State? = nil + var proofs: Common.Proofs.State? = nil + init() {} } @@ -23,7 +28,15 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { case copyRawTransactionButtonTapped } + @CasePathable + enum ChildAction: Sendable, Equatable { + case withdrawals(Common.Accounts.Action) + case deposits(Common.Accounts.Action) + case proofs(Common.Proofs.Action) + } + enum InternalAction: Sendable, Equatable { + case setSections(Common.Sections?) case updateSecondsToExpiration(Date) } @@ -32,15 +45,26 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { var body: some ReducerOf { Reduce(core) + .ifLet(\.withdrawals, action: \.child.withdrawals) { + Common.Accounts() + } + .ifLet(\.deposits, action: \.child.deposits) { + Common.Accounts() + } + .ifLet(\.proofs, action: \.child.proofs) { + Common.Proofs() + } } func reduce(into state: inout State, viewAction: ViewAction) -> Effect { switch viewAction { case .appeared: + // TODO: Replace mocked data with real logic let time = Date().addingTimeInterval(90) state.expiration = .atTime(time) state.secondsToExpiration = Int(time.timeIntervalSinceNow) return startTimer(expirationDate: time) + .merge(with: simulateSections()) case .toggleDisplayModeButtonTapped: switch state.displayMode { @@ -63,6 +87,17 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { func reduce(into state: inout State, internalAction: InternalAction) -> Effect { switch internalAction { + case let .setSections(sections): + guard let sections else { + // TOOD: Show alert to indicate manifest is complex + state.displayMode = .raw(state.exampleRaw) + return .none + } + state.withdrawals = sections.withdrawals + state.deposits = sections.deposits + state.proofs = sections.proofs + return .none + case let .updateSecondsToExpiration(expiration): state.secondsToExpiration = Int(expiration.timeIntervalSinceNow) return .none @@ -71,6 +106,43 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { } private extension PreAuthorizationReview { + func simulateSections() -> Effect { + let resourceBalance: ResourceBalance = .init(resource: .init(resourceAddress: .sampleStokenetXRD, metadata: .init(name: "Radix", symbol: "XRD", isComplete: true)), details: .fungible(.init(isXRD: true, amount: .init(nominalAmount: .five)))) + let idResourceBalance = resourceBalance.asIdentified + + let nftBalance: ResourceBalance = .init(resource: .init(resourceAddress: .sampleMainnetNonFungibleGCMembership, atLedgerState: .init(version: 1, epoch: 2), metadata: .init(name: "GC Member Card", isComplete: true)), details: .nonFungible(.init(id: .sample, data: nil))) + + let accountWithdraw = Common.Account.State( + account: .user(.sampleMainnetAlice), + transfers: [idResourceBalance], + isDeposit: false + ) + let withdrawals = Common.Accounts.State( + accounts: [accountWithdraw], + enableCustomizeGuarantees: false + ) + let accountDeposit = Common.Account.State( + account: .user(.sampleMainnetBob), + transfers: [idResourceBalance], + isDeposit: true + ) + let deposits = Common.Accounts.State( + accounts: [accountDeposit], + enableCustomizeGuarantees: false + ) + + let proofs = Common.Proofs.State(proofs: [ + .init(resourceBalance: nftBalance), + ]) + + let sections = Common.Sections( + withdrawals: withdrawals, + deposits: deposits, + proofs: proofs + ) + return .send(.internal(.setSections(sections))) + } + func startTimer(expirationDate: Date) -> Effect { .run { send in for await _ in self.clock.timer(interval: .seconds(1)) { diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift index c76769dd51..6e787d472a 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift @@ -433,7 +433,7 @@ extension TransactionReview { for (accountAddress, accountDeposits) in accountDeposits { let account = try userAccounts.account(for: accountAddress) let transfers = try await accountDeposits.asyncFlatMap { - try await transferInfo( + let aux = try await transferInfo( resourceQuantifier: $0, newlyCreatedNonFungibles: newlyCreatedNonFungibles, poolInteractions: poolContributions, @@ -445,6 +445,7 @@ extension TransactionReview { type: $0.transferType, defaultDepositGuarantee: defaultDepositGuarantee ) + return aux } .map(\.asIdentified) From c001881df910bfaaa3998062be517508b6ae47ee Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 21 Oct 2024 16:06:51 -0300 Subject: [PATCH 11/63] Accounts and Proofs are now using ObservableState --- .../Sections/Accounts/Accounts+View.swift | 65 +++++-------------- .../Sections/Accounts/Accounts.swift | 14 +++- .../Sections/Proofs/Proofs+View.swift | 11 +--- .../Sections/Proofs/Proofs.swift | 8 ++- 4 files changed, 39 insertions(+), 59 deletions(-) diff --git a/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts+View.swift b/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts+View.swift index e0a35c30a7..28bc3f7dc8 100644 --- a/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts+View.swift +++ b/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts+View.swift @@ -1,27 +1,13 @@ import ComposableArchitecture import SwiftUI -extension InteractionReviewCommon.Accounts.State { - var viewState: InteractionReviewCommon.Accounts.ViewState { - .init(showCustomizeGuaranteesButton: enableCustomizeGuarantees) - } -} - +// MARK: - InteractionReviewCommon.Accounts.View extension InteractionReviewCommon.Accounts { - struct ViewState: Equatable { - let showCustomizeGuaranteesButton: Bool - } - - @MainActor struct View: SwiftUI.View { - private let store: StoreOf - - init(store: StoreOf) { - self.store = store - } + let store: StoreOf var body: some SwiftUI.View { - WithViewStore(store, observe: \.viewState, send: { .view($0) }) { viewStore in + WithPerceptionTracking { Card { VStack(spacing: .small1) { ForEachStore( @@ -29,9 +15,9 @@ extension InteractionReviewCommon.Accounts { content: { InteractionReviewCommon.Account.View(store: $0) } ) - if viewStore.showCustomizeGuaranteesButton { + if store.enableCustomizeGuarantees { Button(L10n.TransactionReview.customizeGuaranteesButtonTitle) { - viewStore.send(.customizeGuaranteesTapped) + store.send(.view(.customizeGuaranteesTapped)) } .textStyle(.body1Header) .foregroundColor(.app.blue2) @@ -45,43 +31,28 @@ extension InteractionReviewCommon.Accounts { } } -extension InteractionReviewCommon.Account.State { - var viewState: InteractionReviewCommon.Account.ViewState { - .init(account: account, transfers: transfers.elements, showApprovedMark: account.isApproved, isDeposit: isDeposit) - } -} - +// MARK: - InteractionReviewCommon.Account.View extension InteractionReviewCommon.Account { - struct ViewState: Equatable { - let account: TransactionReview.ReviewAccount - let transfers: [TransactionReview.Transfer] // FIXME: GK use viewstate? - let showApprovedMark: Bool - let isDeposit: Bool - } - - @MainActor struct View: SwiftUI.View { - private let store: StoreOf - - init(store: StoreOf) { - self.store = store - } + let store: StoreOf var body: some SwiftUI.View { - WithViewStore(store, observe: \.viewState, send: { .view($0) }) { viewStore in + WithPerceptionTracking { InnerCard { - AccountCard(account: viewStore.account) + AccountCard(account: store.account) VStack(spacing: .zero) { - ForEach(viewStore.transfers) { transfer in - TransactionReviewResourceView(transfer: transfer.value, isDeposit: viewStore.isDeposit) { token in - viewStore.send(.transferTapped(transfer.value, token)) + ForEach(store.transfers) { transfer in + TransactionReviewResourceView(transfer: transfer.value, isDeposit: store.isDeposit) { token in + store.send(.view(.transferTapped(transfer.value, token))) } - if transfer.id != viewStore.transfers.last?.id { - Rectangle() - .fill(.app.gray4) - .frame(height: 1) + WithPerceptionTracking { + if transfer.id != store.transfers.last?.id { + Rectangle() + .fill(.app.gray4) + .frame(height: 1) + } } } } diff --git a/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts.swift b/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts.swift index 1fb2448f7d..6d531e11a3 100644 --- a/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts.swift +++ b/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts.swift @@ -3,7 +3,9 @@ import SwiftUI // MARK: - InteractionReviewCommon.Accounts extension InteractionReviewCommon { + @Reducer struct Accounts: Sendable, FeatureReducer { + @ObservableState struct State: Sendable, Hashable { init(accounts: IdentifiedArrayOf, enableCustomizeGuarantees: Bool) { self.accounts = accounts @@ -14,6 +16,8 @@ extension InteractionReviewCommon { let enableCustomizeGuarantees: Bool } + typealias Action = FeatureAction + enum ViewAction: Sendable, Equatable { case customizeGuaranteesTapped } @@ -28,8 +32,6 @@ extension InteractionReviewCommon { case showAsset(ResourceBalance, OnLedgerEntity.NonFungibleToken?) } - init() {} - var body: some ReducerOf { Reduce(core) .forEach(\.accounts, action: /Action.child .. ChildAction.account) { @@ -57,7 +59,9 @@ extension InteractionReviewCommon { // MARK: - InteractionReviewCommon.Account extension InteractionReviewCommon { + @Reducer struct Account: Sendable, FeatureReducer { + @ObservableState struct State: Sendable, Identifiable, Hashable { var id: AccountAddress { account.address } let account: TransactionReview.ReviewAccount @@ -71,6 +75,8 @@ extension InteractionReviewCommon { } } + typealias Action = FeatureAction + enum ViewAction: Sendable, Equatable { case appeared case transferTapped(ResourceBalance, OnLedgerEntity.NonFungibleToken?) @@ -81,7 +87,9 @@ extension InteractionReviewCommon { case showStakeClaim(OnLedgerEntitiesClient.StakeClaim) } - init() {} + var body: some ReducerOf { + Reduce(core) + } func reduce(into state: inout State, viewAction: ViewAction) -> Effect { switch viewAction { diff --git a/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs+View.swift b/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs+View.swift index b2aff3dc37..41196e772a 100644 --- a/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs+View.swift +++ b/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs+View.swift @@ -3,16 +3,11 @@ import SwiftUI // MARK: - InteractionReviewProofs.View extension InteractionReviewCommon.Proofs { - @MainActor struct View: SwiftUI.View { let store: StoreOf - init(store: StoreOf) { - self.store = store - } - var body: some SwiftUI.View { - WithViewStore(store, observe: { $0 }, send: { .view($0) }) { viewStore in + WithPerceptionTracking { VStack(alignment: .leading, spacing: .medium2) { HStack { Text(L10n.TransactionReview.presentingHeading) @@ -24,9 +19,9 @@ extension InteractionReviewCommon.Proofs { Spacer(minLength: 0) } - ForEach(viewStore.proofs) { proof in + ForEach(store.proofs) { proof in ResourceBalanceView(proof.resourceBalance.viewState, appearance: .compact) { - viewStore.send(.proofTapped(proof)) + store.send(.view(.proofTapped(proof))) } } Separator() diff --git a/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift b/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift index c68bc28ee2..8c4689330e 100644 --- a/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift +++ b/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift @@ -2,7 +2,9 @@ import ComposableArchitecture import SwiftUI extension InteractionReviewCommon { + @Reducer struct Proofs: Sendable, FeatureReducer { + @ObservableState struct State: Sendable, Hashable { var proofs: IdentifiedArrayOf @@ -11,6 +13,8 @@ extension InteractionReviewCommon { } } + typealias Action = FeatureAction + enum ViewAction: Sendable, Equatable { case infoTapped case proofTapped(ProofEntity) @@ -20,7 +24,9 @@ extension InteractionReviewCommon { case showAsset(ProofEntity) } - init() {} + var body: some ReducerOf { + Reduce(core) + } func reduce(into state: inout State, viewAction: ViewAction) -> Effect { switch viewAction { From a7711f81ab216793b3b38bdd12f9166f8f216785 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 21 Oct 2024 19:00:28 -0300 Subject: [PATCH 12/63] add sections and clean a bit the UI --- RadixWallet.xcodeproj/project.pbxproj | 4 ++ .../Sections/Proofs/Proofs+View.swift | 4 +- .../Sections/Proofs/Proofs.swift | 7 +-- .../PreAuthorizationReview+Sections.swift | 37 ++++++++++++++ .../PreAuthorizationReview+View.swift | 5 +- .../PreAuthorizationReview.swift | 48 +++++-------------- .../TransactionReview+Sections.swift | 2 +- 7 files changed, 61 insertions(+), 46 deletions(-) create mode 100644 RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+Sections.swift diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index b3c9b87454..24d3345b86 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -723,6 +723,7 @@ 5B272DDB2C36E9D300B74F1F /* AppEventsClient+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B272DDA2C36E9D300B74F1F /* AppEventsClient+Test.swift */; }; 5B27FBD92CC67655002975BE /* HeadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBD82CC67655002975BE /* HeadingView.swift */; }; 5B27FBE02CC6CCBE002975BE /* Sections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBDF2CC6CCBE002975BE /* Sections.swift */; }; + 5B27FBE62CC700F4002975BE /* PreAuthorizationReview+Sections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBE52CC700E5002975BE /* PreAuthorizationReview+Sections.swift */; }; 5B2A45022BD6680400AEC8AD /* ContactSupportClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */; }; 5B2A45042BD6689100AEC8AD /* ContactSupportClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */; }; 5B3C48A92C7E190C00DB160D /* AssetRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B3C48A82C7E190C00DB160D /* AssetRow.swift */; }; @@ -1953,6 +1954,7 @@ 5B272DDA2C36E9D300B74F1F /* AppEventsClient+Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppEventsClient+Test.swift"; sourceTree = ""; }; 5B27FBD82CC67655002975BE /* HeadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadingView.swift; sourceTree = ""; }; 5B27FBDF2CC6CCBE002975BE /* Sections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sections.swift; sourceTree = ""; }; + 5B27FBE52CC700E5002975BE /* PreAuthorizationReview+Sections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationReview+Sections.swift"; sourceTree = ""; }; 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactSupportClient.swift; sourceTree = ""; }; 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactSupportClient+Live.swift"; sourceTree = ""; }; 5B3C48A82C7E190C00DB160D /* AssetRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetRow.swift; sourceTree = ""; }; @@ -5585,6 +5587,7 @@ children = ( 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */, 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */, + 5B27FBE52CC700E5002975BE /* PreAuthorizationReview+Sections.swift */, ); path = PreAuthorizationReview; sourceTree = ""; @@ -8017,6 +8020,7 @@ E7B7A0FD2BBBFB6100EEE900 /* HeaderListViewContainer.swift in Sources */, 48CFC3FA2ADC10D900E77A5C /* SignalingClient.swift in Sources */, 4813B0012BCA48CE0046BCAD /* Stage2MigrateToSargon+ProfileNetwork.swift in Sources */, + 5B27FBE62CC700F4002975BE /* PreAuthorizationReview+Sections.swift in Sources */, A40816332C7E0D08005E65B9 /* StatePackageCodePageRequest.swift in Sources */, 48CFC3692ADC10D900E77A5C /* NonFungibleAssetList+Reducer.swift in Sources */, 48CFC2752ADC10D900E77A5C /* Main+View.swift in Sources */, diff --git a/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs+View.swift b/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs+View.swift index 41196e772a..f1a21b03eb 100644 --- a/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs+View.swift +++ b/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs+View.swift @@ -24,7 +24,9 @@ extension InteractionReviewCommon.Proofs { store.send(.view(.proofTapped(proof))) } } - Separator() + if store.kind == .transaction { + Separator() + } } } } diff --git a/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift b/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift index 8c4689330e..8e54d8f1b8 100644 --- a/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift +++ b/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift @@ -6,11 +6,8 @@ extension InteractionReviewCommon { struct Proofs: Sendable, FeatureReducer { @ObservableState struct State: Sendable, Hashable { - var proofs: IdentifiedArrayOf - - init(proofs: IdentifiedArrayOf) { - self.proofs = proofs - } + let kind: InteractionReviewCommon.Kind + let proofs: IdentifiedArrayOf } typealias Action = FeatureAction diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+Sections.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+Sections.swift new file mode 100644 index 0000000000..ee8b3ec04a --- /dev/null +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+Sections.swift @@ -0,0 +1,37 @@ +extension PreAuthorizationReview { + func simulateSections() async throws -> Common.Sections? { + let xrdBalance: ResourceBalance = .init(resource: .init(resourceAddress: .sampleStokenetXRD, metadata: .init(name: "Radix", symbol: "XRD", isComplete: true)), details: .fungible(.init(isXRD: true, amount: .init(nominalAmount: .five)))) + let idResourceBalance = xrdBalance.asIdentified + + let nftBalance: ResourceBalance = .init(resource: .init(resourceAddress: .sampleMainnetNonFungibleGCMembership, atLedgerState: .init(version: 1, epoch: 2), metadata: .init(name: "GC Member Card", iconURL: .init(string: "https://stokenet-gumball-club.radixdlt.com/assets/member-card.png"), isComplete: true)), details: .nonFungible(.init(id: .sample, data: nil))) + + let accountWithdraw = Common.Account.State( + account: .user(.sampleMainnetAlice), + transfers: [idResourceBalance], + isDeposit: false + ) + let withdrawals = Common.Accounts.State( + accounts: [accountWithdraw], + enableCustomizeGuarantees: false + ) + let accountDeposit = Common.Account.State( + account: .user(.sampleMainnetBob), + transfers: [idResourceBalance], + isDeposit: true + ) + let deposits = Common.Accounts.State( + accounts: [accountDeposit], + enableCustomizeGuarantees: false + ) + + let proofs = Common.Proofs.State(kind: .preAuthorization, proofs: [ + .init(resourceBalance: nftBalance), + ]) + + return Common.Sections( + withdrawals: withdrawals, + deposits: deposits, + proofs: proofs + ) + } +} diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index d50ce7078b..1ae6a5b5a1 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -86,7 +86,7 @@ extension PreAuthorizationReview { Common.HeaderView( kind: .preAuthorization, name: store.dappName, - thumbnail: nil + thumbnail: store.dappThumbnail ) .measurePosition(navTitleID, coordSpace: coordSpace) .padding(.horizontal, .medium3) @@ -153,6 +153,7 @@ extension PreAuthorizationReview { private var proofs: some SwiftUI.View { if let childStore = store.scope(state: \.proofs, action: \.child.proofs) { Common.Proofs.View(store: childStore) + .padding(.horizontal, .small3) } } @@ -191,7 +192,7 @@ extension PreAuthorizationReview { let value = formatTime(seconds: seconds) Text("Valid for the next **\(value)**") } else { - Text("Invalid!") + Text("This subintent is no longer valid!") } } } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 8c6e44179d..bd56234e24 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -5,7 +5,8 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { @ObservableState struct State: Sendable, Hashable { - var dappName: String? = "Collabo.Fi" + var dappName: String? = "CaviarNine" + var dappThumbnail: URL? = .init(string: "https://assets.caviarnine.com/icons/caviarnine_logo_light_400.png") var displayMode: Common.DisplayMode = .detailed var sliderResetDate: Date = .now // TODO: reset when it corresponds @@ -64,7 +65,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { state.expiration = .atTime(time) state.secondsToExpiration = Int(time.timeIntervalSinceNow) return startTimer(expirationDate: time) - .merge(with: simulateSections()) + .merge(with: getSections()) case .toggleDisplayModeButtonTapped: switch state.displayMode { @@ -106,41 +107,14 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { } private extension PreAuthorizationReview { - func simulateSections() -> Effect { - let resourceBalance: ResourceBalance = .init(resource: .init(resourceAddress: .sampleStokenetXRD, metadata: .init(name: "Radix", symbol: "XRD", isComplete: true)), details: .fungible(.init(isXRD: true, amount: .init(nominalAmount: .five)))) - let idResourceBalance = resourceBalance.asIdentified - - let nftBalance: ResourceBalance = .init(resource: .init(resourceAddress: .sampleMainnetNonFungibleGCMembership, atLedgerState: .init(version: 1, epoch: 2), metadata: .init(name: "GC Member Card", isComplete: true)), details: .nonFungible(.init(id: .sample, data: nil))) - - let accountWithdraw = Common.Account.State( - account: .user(.sampleMainnetAlice), - transfers: [idResourceBalance], - isDeposit: false - ) - let withdrawals = Common.Accounts.State( - accounts: [accountWithdraw], - enableCustomizeGuarantees: false - ) - let accountDeposit = Common.Account.State( - account: .user(.sampleMainnetBob), - transfers: [idResourceBalance], - isDeposit: true - ) - let deposits = Common.Accounts.State( - accounts: [accountDeposit], - enableCustomizeGuarantees: false - ) - - let proofs = Common.Proofs.State(proofs: [ - .init(resourceBalance: nftBalance), - ]) - - let sections = Common.Sections( - withdrawals: withdrawals, - deposits: deposits, - proofs: proofs - ) - return .send(.internal(.setSections(sections))) + func getSections() -> Effect { + .run { send in + let sections = try await simulateSections() + await send(.internal(.setSections(sections))) + } catch: { error, send in + loggerGlobal.error("Failed to extract PreAuthorization sections, error: \(error)") + await send(.internal(.setSections(nil))) + } } func startTimer(expirationDate: Date) -> Effect { diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift index 6e787d472a..551fc460a8 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift @@ -343,7 +343,7 @@ extension TransactionReview { guard !proofs.isEmpty else { return nil } - return Common.Proofs.State(proofs: proofs.asIdentified()) + return Common.Proofs.State(kind: .transaction, proofs: proofs.asIdentified()) } private func extractResourceBalanceInfo(specifier: ResourceSpecifier) async throws -> [(ResourceAddress, ResourceBalance.Details)] { From c1ef09dbd91a732e9739b3a57484c3d4c5100d0e Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 21 Oct 2024 19:17:03 -0300 Subject: [PATCH 13/63] move more models under common --- .../AccountCard/AccountCard+DataSource.swift | 2 +- .../InteractionReviewCommon.swift | 5 +++ .../Sections/Accounts/Accounts.swift | 40 +++++++++++++++---- .../Sections/Proofs/Proofs.swift | 4 ++ .../TransactionReview+Sections.swift | 10 ++--- .../TransactionReview.swift | 35 +++------------- .../TransactionReviewGuarantees+View.swift | 4 +- .../TransactionReviewGuarantees.swift | 8 ++-- 8 files changed, 58 insertions(+), 50 deletions(-) diff --git a/RadixWallet/Core/FeaturePrelude/AccountCard/AccountCard+DataSource.swift b/RadixWallet/Core/FeaturePrelude/AccountCard/AccountCard+DataSource.swift index fc2b1d659c..a14f20f2ff 100644 --- a/RadixWallet/Core/FeaturePrelude/AccountCard/AccountCard+DataSource.swift +++ b/RadixWallet/Core/FeaturePrelude/AccountCard/AccountCard+DataSource.swift @@ -48,7 +48,7 @@ extension AccountCard where Trailing == EmptyView, Bottom == EmptyView { ) } - init(kind: Kind = .innerCompact, account: TransactionReview.ReviewAccount) { + init(kind: Kind = .innerCompact, account: InteractionReviewCommon.ReviewAccount) { switch account { case let .user(account): self.init(kind: kind, account: account) diff --git a/RadixWallet/Features/InteractionReviewCommon/InteractionReviewCommon.swift b/RadixWallet/Features/InteractionReviewCommon/InteractionReviewCommon.swift index 296bf3deee..447feeaa84 100644 --- a/RadixWallet/Features/InteractionReviewCommon/InteractionReviewCommon.swift +++ b/RadixWallet/Features/InteractionReviewCommon/InteractionReviewCommon.swift @@ -11,3 +11,8 @@ extension InteractionReviewCommon { case preAuthorization } } + +// MARK: InteractionReviewCommon.Transfer +extension InteractionReviewCommon { + typealias Transfer = IDResourceBalance +} diff --git a/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts.swift b/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts.swift index 6d531e11a3..432196979c 100644 --- a/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts.swift +++ b/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts.swift @@ -64,15 +64,10 @@ extension InteractionReviewCommon { @ObservableState struct State: Sendable, Identifiable, Hashable { var id: AccountAddress { account.address } - let account: TransactionReview.ReviewAccount - var transfers: IdentifiedArrayOf - let isDeposit: Bool - init(account: TransactionReview.ReviewAccount, transfers: IdentifiedArrayOf, isDeposit: Bool) { - self.account = account - self.transfers = transfers - self.isDeposit = isDeposit - } + let account: InteractionReviewCommon.ReviewAccount + var transfers: IdentifiedArrayOf + let isDeposit: Bool } typealias Action = FeatureAction @@ -101,3 +96,32 @@ extension InteractionReviewCommon { } } } + +// Neccessary so that ReviewAccount.user has a proper Account associated (and not the InteractionReviewCommon.Account reducer) +typealias RadixAccount = Account + +// MARK: - InteractionReviewCommon.ReviewAccount +extension InteractionReviewCommon { + enum ReviewAccount: Sendable, Hashable { + case user(RadixAccount) + case external(AccountAddress, approved: Bool) + + var address: AccountAddress { + switch self { + case let .user(account): + account.address + case let .external(address, _): + address + } + } + + var isApproved: Bool { + switch self { + case .user: + false + case let .external(_, approved): + approved + } + } + } +} diff --git a/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift b/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift index 8e54d8f1b8..af236c8941 100644 --- a/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift +++ b/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift @@ -1,6 +1,7 @@ import ComposableArchitecture import SwiftUI +// MARK: - InteractionReviewCommon.Proofs extension InteractionReviewCommon { @Reducer struct Proofs: Sendable, FeatureReducer { @@ -34,7 +35,10 @@ extension InteractionReviewCommon { } } } +} +// MARK: - InteractionReviewCommon.ProofEntity +extension InteractionReviewCommon { struct ProofEntity: Sendable, Identifiable, Hashable { var id: ResourceBalance { resourceBalance } let resourceBalance: ResourceBalance diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift index 551fc460a8..8b627203b8 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift @@ -285,7 +285,7 @@ extension TransactionReview { } } - private func extractUserAccounts(_ allAddress: [AccountAddress]) async throws -> [ReviewAccount] { + private func extractUserAccounts(_ allAddress: [AccountAddress]) async throws -> [Common.ReviewAccount] { let userAccounts = try await accountsClient.getAccountsOnCurrentNetwork() return allAddress @@ -384,8 +384,8 @@ extension TransactionReview { resourceAssociatedDapps: ResourceAssociatedDapps? = nil, networkID: NetworkID ) async throws -> Common.Accounts.State? { - var withdrawals: [ReviewAccount: IdentifiedArrayOf] = [:] - let userAccounts: [ReviewAccount] = try await extractUserAccounts(Array(accountWithdraws.keys)) + var withdrawals: [Common.ReviewAccount: IdentifiedArrayOf] = [:] + let userAccounts: [Common.ReviewAccount] = try await extractUserAccounts(Array(accountWithdraws.keys)) for (accountAddress, resources) in accountWithdraws { let account = try userAccounts.account(for: accountAddress) @@ -425,10 +425,10 @@ extension TransactionReview { resourceAssociatedDapps: ResourceAssociatedDapps? = nil, networkID: NetworkID ) async throws -> Common.Accounts.State? { - let userAccounts: [ReviewAccount] = try await extractUserAccounts(Array(accountDeposits.keys)) + let userAccounts: [Common.ReviewAccount] = try await extractUserAccounts(Array(accountDeposits.keys)) let defaultDepositGuarantee = await appPreferencesClient.getPreferences().transaction.defaultDepositGuarantee - var deposits: [ReviewAccount: IdentifiedArrayOf] = [:] + var deposits: [Common.ReviewAccount: IdentifiedArrayOf] = [:] for (accountAddress, accountDeposits) in accountDeposits { let account = try userAccounts.account(for: accountAddress) diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift index 7ccb26a02c..109038f21c 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift @@ -3,7 +3,6 @@ import SwiftUI // MARK: - TransactionReview struct TransactionReview: Sendable, FeatureReducer { - typealias Transfer = IDResourceBalance typealias Common = InteractionReviewCommon struct State: Sendable, Hashable { @@ -780,36 +779,12 @@ extension TransactionReview { } } -// MARK: Useful types - +// MARK: - TransactionReview.DappEntity extension TransactionReview { struct DappEntity: Sendable, Identifiable, Hashable { let id: DappDefinitionAddress let metadata: OnLedgerEntity.Metadata } - - enum ReviewAccount: Sendable, Hashable { - case user(Account) - case external(AccountAddress, approved: Bool) - - var address: AccountAddress { - switch self { - case let .user(account): - account.address - case let .external(address, _): - address - } - } - - var isApproved: Bool { - switch self { - case .user: - false - case let .external(_, approved): - approved - } - } - } } extension ResourceBalance { @@ -866,13 +841,13 @@ extension TransactionReview.State { mutating func applyGuarantee( _ updated: TransactionGuarantee, - transferID: TransactionReview.Transfer.ID + transferID: InteractionReviewCommon.Transfer.ID ) { guard let accountID = accountID(for: transferID) else { return } deposits?.accounts[id: accountID]?.transfers[id: transferID]?.fungibleGuarantee = updated } - private func accountID(for transferID: TransactionReview.Transfer.ID) -> AccountAddress? { + private func accountID(for transferID: InteractionReviewCommon.Transfer.ID) -> AccountAddress? { for account in deposits?.accounts ?? [] { for transfer in account.transfers { if transfer.id == transferID { @@ -886,10 +861,10 @@ extension TransactionReview.State { // MARK: Helpers -extension [TransactionReview.ReviewAccount] { +extension [InteractionReviewCommon.ReviewAccount] { struct MissingUserAccountError: Error {} - func account(for accountAddress: AccountAddress) throws -> TransactionReview.ReviewAccount { + func account(for accountAddress: AccountAddress) throws -> InteractionReviewCommon.ReviewAccount { guard let account = first(where: { $0.address == accountAddress }) else { loggerGlobal.error("Can't find address that was specified for transfer") throw MissingUserAccountError() diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewGuarantees/TransactionReviewGuarantees+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReviewGuarantees/TransactionReviewGuarantees+View.swift index 21328ccaf8..73b77be67a 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewGuarantees/TransactionReviewGuarantees+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReviewGuarantees/TransactionReviewGuarantees+View.swift @@ -90,8 +90,8 @@ extension TransactionReviewGuarantee.State { extension TransactionReviewGuarantee { struct ViewState: Identifiable, Equatable { - let id: TransactionReview.Transfer.ID - let account: TransactionReview.ReviewAccount + let id: InteractionReviewCommon.Transfer.ID + let account: InteractionReviewCommon.ReviewAccount let fungible: ResourceBalance.ViewState.Fungible } diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewGuarantees/TransactionReviewGuarantees.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReviewGuarantees/TransactionReviewGuarantees.swift index c1213f7a13..11df9b7262 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewGuarantees/TransactionReviewGuarantees.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReviewGuarantees/TransactionReviewGuarantees.swift @@ -60,8 +60,8 @@ struct TransactionReviewGuarantees: Sendable, FeatureReducer { // MARK: - TransactionReviewGuarantee struct TransactionReviewGuarantee: Sendable, FeatureReducer { struct State: Identifiable, Sendable, Hashable { - let id: TransactionReview.Transfer.ID - let account: TransactionReview.ReviewAccount + let id: InteractionReviewCommon.Transfer.ID + let account: InteractionReviewCommon.ReviewAccount let resource: OnLedgerEntity.Resource let thumbnail: Thumbnail.FungibleContent let amount: Decimal192 @@ -70,8 +70,8 @@ struct TransactionReviewGuarantee: Sendable, FeatureReducer { var percentageStepper: MinimumPercentageStepper.State init?( - account: TransactionReview.ReviewAccount, - transfer: TransactionReview.Transfer + account: InteractionReviewCommon.ReviewAccount, + transfer: InteractionReviewCommon.Transfer ) { self.id = transfer.id self.account = account From 78924ad7577b335ec6c42a4da6488e9b994a9d1c Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 21 Oct 2024 19:21:35 -0300 Subject: [PATCH 14/63] rename to InteractionReview --- RadixWallet.xcodeproj/project.pbxproj | 48 ++++++++++++------- .../AccountCard/AccountCard+DataSource.swift | 2 +- .../Components}/HeaderView.swift | 2 +- .../Components}/HeadingView.swift | 2 +- .../Components}/RawTransactionView.swift | 2 +- .../Components}/TransferLineView.swift | 4 +- .../Helpers}/DisplayMode.swift | 2 +- .../Helpers/InteractionReview+Extra.swift} | 2 +- .../InteractionReview.swift} | 12 ++--- .../Sections/Accounts/Accounts+View.swift | 14 +++--- .../Sections/Accounts/Accounts.swift | 26 +++++----- .../Sections/Proofs/Proofs+View.swift | 4 +- .../Sections/Proofs/Proofs.swift | 10 ++-- .../Sections/Sections.swift | 2 +- .../PreAuthorizationReview.swift | 2 +- .../TransactionReview+View.swift | 4 +- .../TransactionReview.swift | 12 ++--- .../TransactionReviewGuarantees+View.swift | 4 +- .../TransactionReviewGuarantees.swift | 8 ++-- 19 files changed, 89 insertions(+), 73 deletions(-) rename RadixWallet/Features/{InteractionReviewCommon => InteractionReview/Components}/HeaderView.swift (96%) rename RadixWallet/Features/{InteractionReviewCommon => InteractionReview/Components}/HeadingView.swift (98%) rename RadixWallet/Features/{InteractionReviewCommon => InteractionReview/Components}/RawTransactionView.swift (97%) rename RadixWallet/Features/{InteractionReviewCommon => InteractionReview/Components}/TransferLineView.swift (81%) rename RadixWallet/Features/{InteractionReviewCommon => InteractionReview/Helpers}/DisplayMode.swift (85%) rename RadixWallet/Features/{InteractionReviewCommon/InteractionReviewCommon+Extra.swift => InteractionReview/Helpers/InteractionReview+Extra.swift} (87%) rename RadixWallet/Features/{InteractionReviewCommon/InteractionReviewCommon.swift => InteractionReview/InteractionReview.swift} (52%) rename RadixWallet/Features/{InteractionReviewCommon => InteractionReview}/Sections/Accounts/Accounts+View.swift (91%) rename RadixWallet/Features/{InteractionReviewCommon => InteractionReview}/Sections/Accounts/Accounts.swift (77%) rename RadixWallet/Features/{InteractionReviewCommon => InteractionReview}/Sections/Proofs/Proofs+View.swift (87%) rename RadixWallet/Features/{InteractionReviewCommon => InteractionReview}/Sections/Proofs/Proofs.swift (80%) rename RadixWallet/Features/{InteractionReviewCommon => InteractionReview}/Sections/Sections.swift (95%) diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index 24d3345b86..1f71e3acc2 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -711,7 +711,7 @@ 48FFFB0D2ADC744700B2B213 /* TextBuilder in Frameworks */ = {isa = PBXBuildFile; productRef = 48FFFB0C2ADC744700B2B213 /* TextBuilder */; }; 5B03E3CF2CC1223000E10A64 /* DisplayMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B03E3CE2CC1222D00E10A64 /* DisplayMode.swift */; }; 5B03E3D12CC127B100E10A64 /* RawTransactionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */; }; - 5B03E3D32CC141D100E10A64 /* InteractionReviewCommon+Extra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B03E3D22CC141C200E10A64 /* InteractionReviewCommon+Extra.swift */; }; + 5B03E3D32CC141D100E10A64 /* InteractionReview+Extra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B03E3D22CC141C200E10A64 /* InteractionReview+Extra.swift */; }; 5B03E3D52CC1487900E10A64 /* TransferLineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */; }; 5B135B392C7636DA004AAD2E /* HiddenEntities+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B135B382C7636DA004AAD2E /* HiddenEntities+View.swift */; }; 5B135B3B2C7636FD004AAD2E /* HiddenEntities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B135B3A2C7636FD004AAD2E /* HiddenEntities.swift */; }; @@ -747,7 +747,7 @@ 5B4A1ABB2CBFEBB000679EE6 /* ProofOfOwnership.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AB82CBFEBB000679EE6 /* ProofOfOwnership.swift */; }; 5B4A1ABF2CC00FB800679EE6 /* PreAuthorizationReview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */; }; 5B4A1AC02CC00FB800679EE6 /* PreAuthorizationReview+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */; }; - 5B4A1AC42CC0125700679EE6 /* InteractionReviewCommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AC32CC0123300679EE6 /* InteractionReviewCommon.swift */; }; + 5B4A1AC42CC0125700679EE6 /* InteractionReview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */; }; 5B4A1AC62CC0151300679EE6 /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */; }; 5B4E1D132CB421EB002FAC2E /* DepositStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4E1D122CB421E3002FAC2E /* DepositStatus.swift */; }; 5B4E1D1F2CB7FE8E002FAC2E /* Sargon in Frameworks */ = {isa = PBXBuildFile; productRef = 5B4E1D1E2CB7FE8E002FAC2E /* Sargon */; }; @@ -1943,7 +1943,7 @@ 48FFFAF12ADC23AC00B2B213 /* Exports.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Exports.swift; sourceTree = ""; }; 5B03E3CE2CC1222D00E10A64 /* DisplayMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayMode.swift; sourceTree = ""; }; 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawTransactionView.swift; sourceTree = ""; }; - 5B03E3D22CC141C200E10A64 /* InteractionReviewCommon+Extra.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InteractionReviewCommon+Extra.swift"; sourceTree = ""; }; + 5B03E3D22CC141C200E10A64 /* InteractionReview+Extra.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InteractionReview+Extra.swift"; sourceTree = ""; }; 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransferLineView.swift; sourceTree = ""; }; 5B135B382C7636DA004AAD2E /* HiddenEntities+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HiddenEntities+View.swift"; sourceTree = ""; }; 5B135B3A2C7636FD004AAD2E /* HiddenEntities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HiddenEntities.swift; sourceTree = ""; }; @@ -1977,7 +1977,7 @@ 5B4A1AB92CBFEBB000679EE6 /* ProofOfOwnership+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProofOfOwnership+View.swift"; sourceTree = ""; }; 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreAuthorizationReview.swift; sourceTree = ""; }; 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationReview+View.swift"; sourceTree = ""; }; - 5B4A1AC32CC0123300679EE6 /* InteractionReviewCommon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractionReviewCommon.swift; sourceTree = ""; }; + 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractionReview.swift; sourceTree = ""; }; 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = ""; }; 5B4E1D122CB421E3002FAC2E /* DepositStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepositStatus.swift; sourceTree = ""; }; 5B526ADA2C876E7C00AF8B72 /* AccountLockerClaimDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountLockerClaimDetails.swift; sourceTree = ""; }; @@ -2722,7 +2722,7 @@ 48CFBCBF2ADC10D800E77A5C /* P2PLinksFeature */, 48CFBCC62ADC10D800E77A5C /* AppFeature */, 48CFBCD02ADC10D800E77A5C /* TransactionReviewFeature */, - 5B4A1AC22CC0120600679EE6 /* InteractionReviewCommon */, + 5B4A1AC22CC0120600679EE6 /* InteractionReview */, 5B4A1ABC2CC00F7F00679EE6 /* PreAuthorizationReview */, 48CFBCF92ADC10D800E77A5C /* DappsAndPersonas */, 48CFBD0E2ADC10D800E77A5C /* HomeFeature */, @@ -5524,6 +5524,26 @@ path = Sections; sourceTree = ""; }; + 5B27FBE72CC70AAA002975BE /* Helpers */ = { + isa = PBXGroup; + children = ( + 5B03E3D22CC141C200E10A64 /* InteractionReview+Extra.swift */, + 5B03E3CE2CC1222D00E10A64 /* DisplayMode.swift */, + ); + path = Helpers; + sourceTree = ""; + }; + 5B27FBE82CC70AC2002975BE /* Components */ = { + isa = PBXGroup; + children = ( + 5B27FBD82CC67655002975BE /* HeadingView.swift */, + 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */, + 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */, + 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */, + ); + path = Components; + sourceTree = ""; + }; 5B2A45002BD667FB00AEC8AD /* ContactSupportClient */ = { isa = PBXGroup; children = ( @@ -5592,19 +5612,15 @@ path = PreAuthorizationReview; sourceTree = ""; }; - 5B4A1AC22CC0120600679EE6 /* InteractionReviewCommon */ = { + 5B4A1AC22CC0120600679EE6 /* InteractionReview */ = { isa = PBXGroup; children = ( - 5B4A1AC32CC0123300679EE6 /* InteractionReviewCommon.swift */, - 5B03E3D22CC141C200E10A64 /* InteractionReviewCommon+Extra.swift */, - 5B27FBD82CC67655002975BE /* HeadingView.swift */, - 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */, - 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */, - 5B03E3CE2CC1222D00E10A64 /* DisplayMode.swift */, - 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */, + 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */, 5B27FBDE2CC6CCA6002975BE /* Sections */, + 5B27FBE82CC70AC2002975BE /* Components */, + 5B27FBE72CC70AAA002975BE /* Helpers */, ); - path = InteractionReviewCommon; + path = InteractionReview; sourceTree = ""; }; 5B526AEB2C89C3C200AF8B72 /* ResourcesVisibilityClient */ = { @@ -7332,7 +7348,7 @@ 48CFC27A2ADC10D900E77A5C /* App+View.swift in Sources */, A40815E72C7E0D08005E65B9 /* ProgrammaticScryptoSborValueU128.swift in Sources */, E7AE2D0E2C07359500830BAA /* FullScreenOverlayCoordinator+Reducer.swift in Sources */, - 5B4A1AC42CC0125700679EE6 /* InteractionReviewCommon.swift in Sources */, + 5B4A1AC42CC0125700679EE6 /* InteractionReview.swift in Sources */, 48CFC3ED2ADC10D900E77A5C /* DataChannelMessage+Codable.swift in Sources */, A408163B2C7E0D08005E65B9 /* TransactionAccountDepositPreValidationAuthorizedDepositorBadge.swift in Sources */, 48CFC5DA2ADC10DA00E77A5C /* PresentationDetentIntrinsicHeight.swift in Sources */, @@ -7594,7 +7610,7 @@ A40816152C7E0D08005E65B9 /* StateEntityMetadataPageRequest.swift in Sources */, 48CFC5972ADC10DA00E77A5C /* ToggleView.swift in Sources */, 5B634AB02C92F6FA004B2FBC /* UpdateP2PLinkName+View.swift in Sources */, - 5B03E3D32CC141D100E10A64 /* InteractionReviewCommon+Extra.swift in Sources */, + 5B03E3D32CC141D100E10A64 /* InteractionReview+Extra.swift in Sources */, 48CFC4892ADC10DA00E77A5C /* EntityMetadata+GWMetadata.swift in Sources */, 48CFC3512ADC10D900E77A5C /* DappHeader.swift in Sources */, A40815742C7E0D08005E65B9 /* EntityNotFoundError.swift in Sources */, diff --git a/RadixWallet/Core/FeaturePrelude/AccountCard/AccountCard+DataSource.swift b/RadixWallet/Core/FeaturePrelude/AccountCard/AccountCard+DataSource.swift index a14f20f2ff..975239527a 100644 --- a/RadixWallet/Core/FeaturePrelude/AccountCard/AccountCard+DataSource.swift +++ b/RadixWallet/Core/FeaturePrelude/AccountCard/AccountCard+DataSource.swift @@ -48,7 +48,7 @@ extension AccountCard where Trailing == EmptyView, Bottom == EmptyView { ) } - init(kind: Kind = .innerCompact, account: InteractionReviewCommon.ReviewAccount) { + init(kind: Kind = .innerCompact, account: InteractionReview.ReviewAccount) { switch account { case let .user(account): self.init(kind: kind, account: account) diff --git a/RadixWallet/Features/InteractionReviewCommon/HeaderView.swift b/RadixWallet/Features/InteractionReview/Components/HeaderView.swift similarity index 96% rename from RadixWallet/Features/InteractionReviewCommon/HeaderView.swift rename to RadixWallet/Features/InteractionReview/Components/HeaderView.swift index 832386b96f..1787dbb5ff 100644 --- a/RadixWallet/Features/InteractionReviewCommon/HeaderView.swift +++ b/RadixWallet/Features/InteractionReview/Components/HeaderView.swift @@ -1,6 +1,6 @@ import SwiftUI -extension InteractionReviewCommon { +extension InteractionReview { struct HeaderView: View { let kind: Kind let name: String? diff --git a/RadixWallet/Features/InteractionReviewCommon/HeadingView.swift b/RadixWallet/Features/InteractionReview/Components/HeadingView.swift similarity index 98% rename from RadixWallet/Features/InteractionReviewCommon/HeadingView.swift rename to RadixWallet/Features/InteractionReview/Components/HeadingView.swift index cfa4ec68f6..0b717a51fc 100644 --- a/RadixWallet/Features/InteractionReviewCommon/HeadingView.swift +++ b/RadixWallet/Features/InteractionReview/Components/HeadingView.swift @@ -1,6 +1,6 @@ import SwiftUI -extension InteractionReviewCommon { +extension InteractionReview { struct HeadingView: View { let heading: String let icon: ImageAsset diff --git a/RadixWallet/Features/InteractionReviewCommon/RawTransactionView.swift b/RadixWallet/Features/InteractionReview/Components/RawTransactionView.swift similarity index 97% rename from RadixWallet/Features/InteractionReviewCommon/RawTransactionView.swift rename to RadixWallet/Features/InteractionReview/Components/RawTransactionView.swift index 40997a0216..a66c7cd3a3 100644 --- a/RadixWallet/Features/InteractionReviewCommon/RawTransactionView.swift +++ b/RadixWallet/Features/InteractionReview/Components/RawTransactionView.swift @@ -1,6 +1,6 @@ import SwiftUI -extension InteractionReviewCommon { +extension InteractionReview { struct RawTransactionView: SwiftUI.View { let transaction: String let copyAction: () -> Void diff --git a/RadixWallet/Features/InteractionReviewCommon/TransferLineView.swift b/RadixWallet/Features/InteractionReview/Components/TransferLineView.swift similarity index 81% rename from RadixWallet/Features/InteractionReviewCommon/TransferLineView.swift rename to RadixWallet/Features/InteractionReview/Components/TransferLineView.swift index 6e71aba660..501d5314d8 100644 --- a/RadixWallet/Features/InteractionReviewCommon/TransferLineView.swift +++ b/RadixWallet/Features/InteractionReview/Components/TransferLineView.swift @@ -1,7 +1,7 @@ import SwiftUI -extension InteractionReviewCommon { - typealias Common = InteractionReviewCommon +extension InteractionReview { + typealias Common = InteractionReview struct TransferLineView: View { var body: some View { diff --git a/RadixWallet/Features/InteractionReviewCommon/DisplayMode.swift b/RadixWallet/Features/InteractionReview/Helpers/DisplayMode.swift similarity index 85% rename from RadixWallet/Features/InteractionReviewCommon/DisplayMode.swift rename to RadixWallet/Features/InteractionReview/Helpers/DisplayMode.swift index aa3777815d..1c6dfce84e 100644 --- a/RadixWallet/Features/InteractionReviewCommon/DisplayMode.swift +++ b/RadixWallet/Features/InteractionReview/Helpers/DisplayMode.swift @@ -1,6 +1,6 @@ import Foundation -extension InteractionReviewCommon { +extension InteractionReview { enum DisplayMode: Sendable, Hashable { case detailed case raw(String) diff --git a/RadixWallet/Features/InteractionReviewCommon/InteractionReviewCommon+Extra.swift b/RadixWallet/Features/InteractionReview/Helpers/InteractionReview+Extra.swift similarity index 87% rename from RadixWallet/Features/InteractionReviewCommon/InteractionReviewCommon+Extra.swift rename to RadixWallet/Features/InteractionReview/Helpers/InteractionReview+Extra.swift index b30db293a9..3e23aeab16 100644 --- a/RadixWallet/Features/InteractionReviewCommon/InteractionReviewCommon+Extra.swift +++ b/RadixWallet/Features/InteractionReview/Helpers/InteractionReview+Extra.swift @@ -1,4 +1,4 @@ -extension InteractionReviewCommon { +extension InteractionReview { static let gradientBackground: LinearGradient = .init( stops: [ .init(color: .app.gray5, location: 0), diff --git a/RadixWallet/Features/InteractionReviewCommon/InteractionReviewCommon.swift b/RadixWallet/Features/InteractionReview/InteractionReview.swift similarity index 52% rename from RadixWallet/Features/InteractionReviewCommon/InteractionReviewCommon.swift rename to RadixWallet/Features/InteractionReview/InteractionReview.swift index 447feeaa84..b30c7330bd 100644 --- a/RadixWallet/Features/InteractionReviewCommon/InteractionReviewCommon.swift +++ b/RadixWallet/Features/InteractionReview/InteractionReview.swift @@ -1,18 +1,18 @@ import SwiftUI -// MARK: - InteractionReviewCommon +// MARK: - InteractionReview /// Namespace to group every component common to `TransactionReview` and `PreAuthorizationReview` -enum InteractionReviewCommon {} +enum InteractionReview {} -// MARK: InteractionReviewCommon.Kind -extension InteractionReviewCommon { +// MARK: InteractionReview.Kind +extension InteractionReview { enum Kind: Sendable, Hashable { case transaction case preAuthorization } } -// MARK: InteractionReviewCommon.Transfer -extension InteractionReviewCommon { +// MARK: InteractionReview.Transfer +extension InteractionReview { typealias Transfer = IDResourceBalance } diff --git a/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts+View.swift b/RadixWallet/Features/InteractionReview/Sections/Accounts/Accounts+View.swift similarity index 91% rename from RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts+View.swift rename to RadixWallet/Features/InteractionReview/Sections/Accounts/Accounts+View.swift index 28bc3f7dc8..52b461852b 100644 --- a/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Accounts/Accounts+View.swift @@ -1,10 +1,10 @@ import ComposableArchitecture import SwiftUI -// MARK: - InteractionReviewCommon.Accounts.View -extension InteractionReviewCommon.Accounts { +// MARK: - InteractionReview.Accounts.View +extension InteractionReview.Accounts { struct View: SwiftUI.View { - let store: StoreOf + let store: StoreOf var body: some SwiftUI.View { WithPerceptionTracking { @@ -12,7 +12,7 @@ extension InteractionReviewCommon.Accounts { VStack(spacing: .small1) { ForEachStore( store.scope(state: \.accounts, action: \.child.account), - content: { InteractionReviewCommon.Account.View(store: $0) } + content: { InteractionReview.Account.View(store: $0) } ) if store.enableCustomizeGuarantees { @@ -31,10 +31,10 @@ extension InteractionReviewCommon.Accounts { } } -// MARK: - InteractionReviewCommon.Account.View -extension InteractionReviewCommon.Account { +// MARK: - InteractionReview.Account.View +extension InteractionReview.Account { struct View: SwiftUI.View { - let store: StoreOf + let store: StoreOf var body: some SwiftUI.View { WithPerceptionTracking { diff --git a/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts.swift b/RadixWallet/Features/InteractionReview/Sections/Accounts/Accounts.swift similarity index 77% rename from RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts.swift rename to RadixWallet/Features/InteractionReview/Sections/Accounts/Accounts.swift index 432196979c..a5dccd4236 100644 --- a/RadixWallet/Features/InteractionReviewCommon/Sections/Accounts/Accounts.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Accounts/Accounts.swift @@ -1,18 +1,18 @@ import ComposableArchitecture import SwiftUI -// MARK: - InteractionReviewCommon.Accounts -extension InteractionReviewCommon { +// MARK: - InteractionReview.Accounts +extension InteractionReview { @Reducer struct Accounts: Sendable, FeatureReducer { @ObservableState struct State: Sendable, Hashable { - init(accounts: IdentifiedArrayOf, enableCustomizeGuarantees: Bool) { + init(accounts: IdentifiedArrayOf, enableCustomizeGuarantees: Bool) { self.accounts = accounts self.enableCustomizeGuarantees = enableCustomizeGuarantees } - var accounts: IdentifiedArrayOf + var accounts: IdentifiedArrayOf let enableCustomizeGuarantees: Bool } @@ -24,7 +24,7 @@ extension InteractionReviewCommon { @CasePathable enum ChildAction: Sendable, Equatable { - case account(id: AccountAddress, action: InteractionReviewCommon.Account.Action) + case account(id: AccountAddress, action: InteractionReview.Account.Action) } enum DelegateAction: Sendable, Equatable { @@ -35,7 +35,7 @@ extension InteractionReviewCommon { var body: some ReducerOf { Reduce(core) .forEach(\.accounts, action: /Action.child .. ChildAction.account) { - InteractionReviewCommon.Account() + InteractionReview.Account() } } @@ -57,16 +57,16 @@ extension InteractionReviewCommon { } } -// MARK: - InteractionReviewCommon.Account -extension InteractionReviewCommon { +// MARK: - InteractionReview.Account +extension InteractionReview { @Reducer struct Account: Sendable, FeatureReducer { @ObservableState struct State: Sendable, Identifiable, Hashable { var id: AccountAddress { account.address } - let account: InteractionReviewCommon.ReviewAccount - var transfers: IdentifiedArrayOf + let account: InteractionReview.ReviewAccount + var transfers: IdentifiedArrayOf let isDeposit: Bool } @@ -97,11 +97,11 @@ extension InteractionReviewCommon { } } -// Neccessary so that ReviewAccount.user has a proper Account associated (and not the InteractionReviewCommon.Account reducer) +// Neccessary so that ReviewAccount.user has a proper Account associated (and not the InteractionReview.Account reducer) typealias RadixAccount = Account -// MARK: - InteractionReviewCommon.ReviewAccount -extension InteractionReviewCommon { +// MARK: - InteractionReview.ReviewAccount +extension InteractionReview { enum ReviewAccount: Sendable, Hashable { case user(RadixAccount) case external(AccountAddress, approved: Bool) diff --git a/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs+View.swift b/RadixWallet/Features/InteractionReview/Sections/Proofs/Proofs+View.swift similarity index 87% rename from RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs+View.swift rename to RadixWallet/Features/InteractionReview/Sections/Proofs/Proofs+View.swift index f1a21b03eb..02fa22af68 100644 --- a/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Proofs/Proofs+View.swift @@ -2,9 +2,9 @@ import ComposableArchitecture import SwiftUI // MARK: - InteractionReviewProofs.View -extension InteractionReviewCommon.Proofs { +extension InteractionReview.Proofs { struct View: SwiftUI.View { - let store: StoreOf + let store: StoreOf var body: some SwiftUI.View { WithPerceptionTracking { diff --git a/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift b/RadixWallet/Features/InteractionReview/Sections/Proofs/Proofs.swift similarity index 80% rename from RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift rename to RadixWallet/Features/InteractionReview/Sections/Proofs/Proofs.swift index af236c8941..d67401ae93 100644 --- a/RadixWallet/Features/InteractionReviewCommon/Sections/Proofs/Proofs.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Proofs/Proofs.swift @@ -1,13 +1,13 @@ import ComposableArchitecture import SwiftUI -// MARK: - InteractionReviewCommon.Proofs -extension InteractionReviewCommon { +// MARK: - InteractionReview.Proofs +extension InteractionReview { @Reducer struct Proofs: Sendable, FeatureReducer { @ObservableState struct State: Sendable, Hashable { - let kind: InteractionReviewCommon.Kind + let kind: InteractionReview.Kind let proofs: IdentifiedArrayOf } @@ -37,8 +37,8 @@ extension InteractionReviewCommon { } } -// MARK: - InteractionReviewCommon.ProofEntity -extension InteractionReviewCommon { +// MARK: - InteractionReview.ProofEntity +extension InteractionReview { struct ProofEntity: Sendable, Identifiable, Hashable { var id: ResourceBalance { resourceBalance } let resourceBalance: ResourceBalance diff --git a/RadixWallet/Features/InteractionReviewCommon/Sections/Sections.swift b/RadixWallet/Features/InteractionReview/Sections/Sections.swift similarity index 95% rename from RadixWallet/Features/InteractionReviewCommon/Sections/Sections.swift rename to RadixWallet/Features/InteractionReview/Sections/Sections.swift index d2dba842c4..0c6a967ebd 100644 --- a/RadixWallet/Features/InteractionReviewCommon/Sections/Sections.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections.swift @@ -1,6 +1,6 @@ import Foundation -extension InteractionReviewCommon { +extension InteractionReview { struct Sections: Sendable, Hashable { var withdrawals: Accounts.State? = nil var dAppsUsed: TransactionReviewDappsUsed.State? = nil diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index bd56234e24..629629981d 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -1,7 +1,7 @@ // MARK: - PreAuthorizationReview @Reducer struct PreAuthorizationReview: Sendable, FeatureReducer { - typealias Common = InteractionReviewCommon + typealias Common = InteractionReview @ObservableState struct State: Sendable, Hashable { diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index 080d5bd33b..28c3df3782 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -508,7 +508,7 @@ private extension View { // MARK: - ExpandableTransactionHeading struct ExpandableTransactionHeading: View { - typealias Common = InteractionReviewCommon + typealias Common = InteractionReview let heading: Common.HeadingView let isExpanded: Bool @@ -549,7 +549,7 @@ extension TransactionReview { typealias ValidatorState = ValidatorView.ViewState struct ValidatorsView: SwiftUI.View { - let heading: InteractionReviewCommon.HeadingView + let heading: InteractionReview.HeadingView let viewState: ViewState let action: () -> Void diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift index 109038f21c..ac94e8a1ab 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift @@ -3,7 +3,7 @@ import SwiftUI // MARK: - TransactionReview struct TransactionReview: Sendable, FeatureReducer { - typealias Common = InteractionReviewCommon + typealias Common = InteractionReview struct State: Sendable, Hashable { var displayMode: Common.DisplayMode = .detailed @@ -595,7 +595,7 @@ extension AlertState { } } -extension Collection { +extension Collection { var customizableGuarantees: [TransactionReviewGuarantee.State] { flatMap { account in account.transfers.compactMap { .init(account: account.account, transfer: $0) } @@ -841,13 +841,13 @@ extension TransactionReview.State { mutating func applyGuarantee( _ updated: TransactionGuarantee, - transferID: InteractionReviewCommon.Transfer.ID + transferID: InteractionReview.Transfer.ID ) { guard let accountID = accountID(for: transferID) else { return } deposits?.accounts[id: accountID]?.transfers[id: transferID]?.fungibleGuarantee = updated } - private func accountID(for transferID: InteractionReviewCommon.Transfer.ID) -> AccountAddress? { + private func accountID(for transferID: InteractionReview.Transfer.ID) -> AccountAddress? { for account in deposits?.accounts ?? [] { for transfer in account.transfers { if transfer.id == transferID { @@ -861,10 +861,10 @@ extension TransactionReview.State { // MARK: Helpers -extension [InteractionReviewCommon.ReviewAccount] { +extension [InteractionReview.ReviewAccount] { struct MissingUserAccountError: Error {} - func account(for accountAddress: AccountAddress) throws -> InteractionReviewCommon.ReviewAccount { + func account(for accountAddress: AccountAddress) throws -> InteractionReview.ReviewAccount { guard let account = first(where: { $0.address == accountAddress }) else { loggerGlobal.error("Can't find address that was specified for transfer") throw MissingUserAccountError() diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewGuarantees/TransactionReviewGuarantees+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReviewGuarantees/TransactionReviewGuarantees+View.swift index 73b77be67a..6acc7b291e 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewGuarantees/TransactionReviewGuarantees+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReviewGuarantees/TransactionReviewGuarantees+View.swift @@ -90,8 +90,8 @@ extension TransactionReviewGuarantee.State { extension TransactionReviewGuarantee { struct ViewState: Identifiable, Equatable { - let id: InteractionReviewCommon.Transfer.ID - let account: InteractionReviewCommon.ReviewAccount + let id: InteractionReview.Transfer.ID + let account: InteractionReview.ReviewAccount let fungible: ResourceBalance.ViewState.Fungible } diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewGuarantees/TransactionReviewGuarantees.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReviewGuarantees/TransactionReviewGuarantees.swift index 11df9b7262..30e460825c 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewGuarantees/TransactionReviewGuarantees.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReviewGuarantees/TransactionReviewGuarantees.swift @@ -60,8 +60,8 @@ struct TransactionReviewGuarantees: Sendable, FeatureReducer { // MARK: - TransactionReviewGuarantee struct TransactionReviewGuarantee: Sendable, FeatureReducer { struct State: Identifiable, Sendable, Hashable { - let id: InteractionReviewCommon.Transfer.ID - let account: InteractionReviewCommon.ReviewAccount + let id: InteractionReview.Transfer.ID + let account: InteractionReview.ReviewAccount let resource: OnLedgerEntity.Resource let thumbnail: Thumbnail.FungibleContent let amount: Decimal192 @@ -70,8 +70,8 @@ struct TransactionReviewGuarantee: Sendable, FeatureReducer { var percentageStepper: MinimumPercentageStepper.State init?( - account: InteractionReviewCommon.ReviewAccount, - transfer: InteractionReviewCommon.Transfer + account: InteractionReview.ReviewAccount, + transfer: InteractionReview.Transfer ) { self.id = transfer.id self.account = account From a24e6ae8d84d61c210243dae4194b1d259e93f08 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 21 Oct 2024 19:34:08 -0300 Subject: [PATCH 15/63] move ValidatorsView --- RadixWallet.xcodeproj/project.pbxproj | 4 + .../Components/ValidatorsView.swift | 74 +++++++++++++++ .../InteractionReview/Sections/Sections.swift | 6 +- .../TransactionReview+Sections.swift | 4 +- .../TransactionReview+View.swift | 91 ++----------------- .../TransactionReview.swift | 6 +- 6 files changed, 95 insertions(+), 90 deletions(-) create mode 100644 RadixWallet/Features/InteractionReview/Components/ValidatorsView.swift diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index 1f71e3acc2..353f24c05f 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -724,6 +724,7 @@ 5B27FBD92CC67655002975BE /* HeadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBD82CC67655002975BE /* HeadingView.swift */; }; 5B27FBE02CC6CCBE002975BE /* Sections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBDF2CC6CCBE002975BE /* Sections.swift */; }; 5B27FBE62CC700F4002975BE /* PreAuthorizationReview+Sections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBE52CC700E5002975BE /* PreAuthorizationReview+Sections.swift */; }; + 5B27FBEA2CC70CA1002975BE /* ValidatorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBE92CC70C9D002975BE /* ValidatorsView.swift */; }; 5B2A45022BD6680400AEC8AD /* ContactSupportClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */; }; 5B2A45042BD6689100AEC8AD /* ContactSupportClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */; }; 5B3C48A92C7E190C00DB160D /* AssetRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B3C48A82C7E190C00DB160D /* AssetRow.swift */; }; @@ -1955,6 +1956,7 @@ 5B27FBD82CC67655002975BE /* HeadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadingView.swift; sourceTree = ""; }; 5B27FBDF2CC6CCBE002975BE /* Sections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sections.swift; sourceTree = ""; }; 5B27FBE52CC700E5002975BE /* PreAuthorizationReview+Sections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationReview+Sections.swift"; sourceTree = ""; }; + 5B27FBE92CC70C9D002975BE /* ValidatorsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorsView.swift; sourceTree = ""; }; 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactSupportClient.swift; sourceTree = ""; }; 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactSupportClient+Live.swift"; sourceTree = ""; }; 5B3C48A82C7E190C00DB160D /* AssetRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetRow.swift; sourceTree = ""; }; @@ -5540,6 +5542,7 @@ 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */, 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */, 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */, + 5B27FBE92CC70C9D002975BE /* ValidatorsView.swift */, ); path = Components; sourceTree = ""; @@ -8329,6 +8332,7 @@ 48CFC2D82ADC10D900E77A5C /* ChooseAccounts+View.swift in Sources */, 48CFC2462ADC10D900E77A5C /* AddAssets+View.swift in Sources */, A408162B2C7E0D08005E65B9 /* StateNonFungibleDetailsResponseItem.swift in Sources */, + 5B27FBEA2CC70CA1002975BE /* ValidatorsView.swift in Sources */, A40815F32C7E0D08005E65B9 /* ResourceHoldersRequest.swift in Sources */, A40815F22C7E0D08005E65B9 /* ResourceHoldersCollectionNonFungibleResourceItem.swift in Sources */, 48D5F3932BD8DDB9000DE964 /* DebugSettingsCoordinator+View.swift in Sources */, diff --git a/RadixWallet/Features/InteractionReview/Components/ValidatorsView.swift b/RadixWallet/Features/InteractionReview/Components/ValidatorsView.swift new file mode 100644 index 0000000000..1098a0dee3 --- /dev/null +++ b/RadixWallet/Features/InteractionReview/Components/ValidatorsView.swift @@ -0,0 +1,74 @@ +import SwiftUI + +extension InteractionReview { + typealias ValidatorsState = ValidatorsView.ViewState + typealias ValidatorState = ValidatorView.ViewState + + struct ValidatorsView: SwiftUI.View { + let heading: InteractionReview.HeadingView + let viewState: ViewState + let action: () -> Void + + var body: some SwiftUI.View { + VStack(alignment: .leading, spacing: .small2) { + ExpandableTransactionHeading(heading: heading, isExpanded: viewState.isExpanded, action: action) + + if viewState.isExpanded { + VStack(spacing: .small2) { + ForEach(viewState.validators) { validator in + ValidatorView(viewState: validator) + } + } + .transition(.opacity.combined(with: .scale(scale: 0.95))) + } + } + } + + struct ViewState: Hashable, Sendable { + let validators: [ValidatorView.ViewState] + var isExpanded: Bool + + init(validators: [ValidatorView.ViewState], isExpanded: Bool = true) { + self.validators = validators + self.isExpanded = isExpanded + } + } + } + + struct ValidatorView: SwiftUI.View { + let viewState: ViewState + + struct ViewState: Hashable, Sendable, Identifiable { + var id: ValidatorAddress { address } + let address: ValidatorAddress + let name: String? + let thumbnail: URL? + } + + var body: some SwiftUI.View { + Card { + HStack(spacing: .zero) { + Thumbnail(.validator, url: viewState.thumbnail) + .padding(.trailing, .medium3) + + VStack(alignment: .leading, spacing: .zero) { + if let name = viewState.name { + Text(name) + .lineSpacing(-6) + .lineLimit(1) + .textStyle(.secondaryHeader) + .foregroundColor(.app.gray1) + } + + AddressView(.address(.validator(viewState.address))) + } + + Spacer(minLength: 0) + } + .frame(minHeight: .plainListRowMinHeight) + .padding(.horizontal, .medium3) + .contentShape(Rectangle()) + } + } + } +} diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections.swift b/RadixWallet/Features/InteractionReview/Sections/Sections.swift index 0c6a967ebd..48b76aa4c8 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections.swift @@ -9,9 +9,9 @@ extension InteractionReview { var contributingToPools: TransactionReviewPools.State? = nil var redeemingFromPools: TransactionReviewPools.State? = nil - var stakingToValidators: TransactionReview.ValidatorsState? = nil - var unstakingFromValidators: TransactionReview.ValidatorsState? = nil - var claimingFromValidators: TransactionReview.ValidatorsState? = nil + var stakingToValidators: InteractionReview.ValidatorsState? = nil + var unstakingFromValidators: InteractionReview.ValidatorsState? = nil + var claimingFromValidators: InteractionReview.ValidatorsState? = nil var accountDepositSetting: TransactionReview.DepositSettingState? = nil var accountDepositExceptions: TransactionReview.DepositExceptionsState? = nil diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift index 8b627203b8..ebba214ce6 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift @@ -463,7 +463,7 @@ extension TransactionReview { return .init(accounts: depositAccounts, enableCustomizeGuarantees: requiresGuarantees) } - func extractValidators(for addresses: [ValidatorAddress]) async throws -> ValidatorsState? { + func extractValidators(for addresses: [ValidatorAddress]) async throws -> Common.ValidatorsState? { guard !addresses.isEmpty else { return nil } let validators = try await onLedgerEntitiesClient.getEntities( @@ -471,7 +471,7 @@ extension TransactionReview { metadataKeys: .resourceMetadataKeys ) - .compactMap { entity -> ValidatorState? in + .compactMap { entity -> Common.ValidatorState? in guard let validator = entity.validator else { return nil } return .init( address: validator.address, diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index 28c3df3782..0b9a1638b0 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -67,9 +67,9 @@ extension TransactionReview { let viewRawTransactionButtonState: ControlState let proposingDappMetadata: DappMetadata.Ledger? - let stakingToValidators: ValidatorsState? - let unstakingFromValidators: ValidatorsState? - let claimingFromValidators: ValidatorsState? + let stakingToValidators: Common.ValidatorsState? + let unstakingFromValidators: Common.ValidatorsState? + let claimingFromValidators: Common.ValidatorsState? let depositSettingSection: DepositSettingState? let depositExceptionsSection: DepositExceptionsState? @@ -312,20 +312,20 @@ extension TransactionReview { } } - private func stakingToValidatorsSection(_ viewState: TransactionReview.ValidatorsView.ViewState) -> some SwiftUI.View { - ValidatorsView(heading: .stakingToValidators, viewState: viewState) { + private func stakingToValidatorsSection(_ viewState: InteractionReview.ValidatorsView.ViewState) -> some SwiftUI.View { + Common.ValidatorsView(heading: .stakingToValidators, viewState: viewState) { store.send(.view(.expandStakingToValidatorsTapped)) } } - private func unstakingFromValidatorsSection(_ viewState: TransactionReview.ValidatorsView.ViewState) -> some SwiftUI.View { - ValidatorsView(heading: .unstakingFromValidators, viewState: viewState) { + private func unstakingFromValidatorsSection(_ viewState: InteractionReview.ValidatorsView.ViewState) -> some SwiftUI.View { + Common.ValidatorsView(heading: .unstakingFromValidators, viewState: viewState) { store.send(.view(.expandUnstakingFromValidatorsTapped)) } } - private func claimingFromValidatorsSection(_ viewState: TransactionReview.ValidatorsView.ViewState) -> some SwiftUI.View { - ValidatorsView(heading: .claimingFromValidators, viewState: viewState) { + private func claimingFromValidatorsSection(_ viewState: InteractionReview.ValidatorsView.ViewState) -> some SwiftUI.View { + Common.ValidatorsView(heading: .claimingFromValidators, viewState: viewState) { store.send(.view(.expandClaimingFromValidatorsTapped)) } } @@ -544,79 +544,6 @@ struct TransactionMessageView: View { } } -extension TransactionReview { - typealias ValidatorsState = ValidatorsView.ViewState - typealias ValidatorState = ValidatorView.ViewState - - struct ValidatorsView: SwiftUI.View { - let heading: InteractionReview.HeadingView - let viewState: ViewState - let action: () -> Void - - var body: some SwiftUI.View { - VStack(alignment: .leading, spacing: .small2) { - ExpandableTransactionHeading(heading: heading, isExpanded: viewState.isExpanded, action: action) - - if viewState.isExpanded { - VStack(spacing: .small2) { - ForEach(viewState.validators) { validator in - ValidatorView(viewState: validator) - } - } - .transition(.opacity.combined(with: .scale(scale: 0.95))) - } - } - } - - struct ViewState: Hashable, Sendable { - let validators: [ValidatorView.ViewState] - var isExpanded: Bool - - init(validators: [ValidatorView.ViewState], isExpanded: Bool = true) { - self.validators = validators - self.isExpanded = isExpanded - } - } - } - - struct ValidatorView: SwiftUI.View { - let viewState: ViewState - - struct ViewState: Hashable, Sendable, Identifiable { - var id: ValidatorAddress { address } - let address: ValidatorAddress - let name: String? - let thumbnail: URL? - } - - var body: some SwiftUI.View { - Card { - HStack(spacing: .zero) { - Thumbnail(.validator, url: viewState.thumbnail) - .padding(.trailing, .medium3) - - VStack(alignment: .leading, spacing: .zero) { - if let name = viewState.name { - Text(name) - .lineSpacing(-6) - .lineLimit(1) - .textStyle(.secondaryHeader) - .foregroundColor(.app.gray1) - } - - AddressView(.address(.validator(viewState.address))) - } - - Spacer(minLength: 0) - } - .frame(minHeight: .plainListRowMinHeight) - .padding(.horizontal, .medium3) - .contentShape(Rectangle()) - } - } - } -} - #if DEBUG import ComposableArchitecture import SwiftUI diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift index ac94e8a1ab..782c5e4941 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift @@ -27,9 +27,9 @@ struct TransactionReview: Sendable, FeatureReducer { var redeemingFromPools: TransactionReviewPools.State? = nil var deposits: Common.Accounts.State? = nil - var stakingToValidators: ValidatorsState? = nil - var unstakingFromValidators: ValidatorsState? = nil - var claimingFromValidators: ValidatorsState? = nil + var stakingToValidators: Common.ValidatorsState? = nil + var unstakingFromValidators: Common.ValidatorsState? = nil + var claimingFromValidators: Common.ValidatorsState? = nil var accountDepositSetting: DepositSettingState? = nil var accountDepositExceptions: DepositExceptionsState? = nil From c49662f841222d3039cd1a47ee30b299568a369b Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 21 Oct 2024 19:40:09 -0300 Subject: [PATCH 16/63] move ExpandableHeadingView and UnknownDappsComponents --- RadixWallet.xcodeproj/project.pbxproj | 40 ++++++++++++++++--- .../Components/ExpandableHeadingView.swift | 25 ++++++++++++ .../Components/ValidatorsView.swift | 2 +- .../UnknownDappComponents+View.swift | 23 +++++------ .../UnknownDappComponents.swift | 34 ++++++++++++++++ .../Helpers/InteractionReview+Typealias.swift | 3 ++ .../InteractionReview/Helpers/Kind.swift | 9 +++++ .../InteractionReview/InteractionReview.swift | 13 ------ .../TransactionReview+View.swift | 31 ++------------ .../TransactionReview.swift | 6 +-- .../UnknownDappComponents+Reducer.swift | 22 ---------- 11 files changed, 122 insertions(+), 86 deletions(-) create mode 100644 RadixWallet/Features/InteractionReview/Components/ExpandableHeadingView.swift rename RadixWallet/Features/{TransactionReviewFeature/TransactionReviewDapps => InteractionReview/Destinations/UnknownDappComponents}/UnknownDappComponents+View.swift (59%) create mode 100644 RadixWallet/Features/InteractionReview/Destinations/UnknownDappComponents/UnknownDappComponents.swift create mode 100644 RadixWallet/Features/InteractionReview/Helpers/InteractionReview+Typealias.swift create mode 100644 RadixWallet/Features/InteractionReview/Helpers/Kind.swift delete mode 100644 RadixWallet/Features/TransactionReviewFeature/TransactionReviewDapps/UnknownDappComponents+Reducer.swift diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index 353f24c05f..78a0f8b313 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -725,6 +725,10 @@ 5B27FBE02CC6CCBE002975BE /* Sections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBDF2CC6CCBE002975BE /* Sections.swift */; }; 5B27FBE62CC700F4002975BE /* PreAuthorizationReview+Sections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBE52CC700E5002975BE /* PreAuthorizationReview+Sections.swift */; }; 5B27FBEA2CC70CA1002975BE /* ValidatorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBE92CC70C9D002975BE /* ValidatorsView.swift */; }; + 5B27FBEC2CC70E87002975BE /* ExpandableHeadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBEB2CC70E87002975BE /* ExpandableHeadingView.swift */; }; + 5B27FBEE2CC70F2D002975BE /* InteractionReview+Typealias.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBED2CC70F2D002975BE /* InteractionReview+Typealias.swift */; }; + 5B27FBF02CC70F59002975BE /* Kind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBEF2CC70F57002975BE /* Kind.swift */; }; + 5B27FBF52CC713B6002975BE /* UnknownDappComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBF42CC713B5002975BE /* UnknownDappComponents.swift */; }; 5B2A45022BD6680400AEC8AD /* ContactSupportClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */; }; 5B2A45042BD6689100AEC8AD /* ContactSupportClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */; }; 5B3C48A92C7E190C00DB160D /* AssetRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B3C48A82C7E190C00DB160D /* AssetRow.swift */; }; @@ -815,7 +819,6 @@ 8338B9E52AFAB20700D1D8EA /* TransactionFee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8338B9E42AFAB20700D1D8EA /* TransactionFee.swift */; }; 834B651F2B972E5100B7E1E8 /* NPSSurvey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 834B651E2B972E5100B7E1E8 /* NPSSurvey.swift */; }; 835F196D2B3581C300E0B71D /* UnknownDappComponents+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 835F196C2B3581C300E0B71D /* UnknownDappComponents+View.swift */; }; - 836878612B4551910029C808 /* UnknownDappComponents+Reducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 836878602B4551910029C808 /* UnknownDappComponents+Reducer.swift */; }; 8370FC5C2B99C780007AD882 /* NPSSurveyClient+Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8370FC5B2B99C780007AD882 /* NPSSurveyClient+Interface.swift */; }; 8381C8B02BBD2CD400A470B4 /* TokenPriceCientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8381C8AF2BBD2CD400A470B4 /* TokenPriceCientTests.swift */; }; 8381C8B32BC0619100A470B4 /* RadixConnectMobile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8381C8B22BC0619100A470B4 /* RadixConnectMobile.swift */; }; @@ -1957,6 +1960,10 @@ 5B27FBDF2CC6CCBE002975BE /* Sections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sections.swift; sourceTree = ""; }; 5B27FBE52CC700E5002975BE /* PreAuthorizationReview+Sections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationReview+Sections.swift"; sourceTree = ""; }; 5B27FBE92CC70C9D002975BE /* ValidatorsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorsView.swift; sourceTree = ""; }; + 5B27FBEB2CC70E87002975BE /* ExpandableHeadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableHeadingView.swift; sourceTree = ""; }; + 5B27FBED2CC70F2D002975BE /* InteractionReview+Typealias.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InteractionReview+Typealias.swift"; sourceTree = ""; }; + 5B27FBEF2CC70F57002975BE /* Kind.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Kind.swift; sourceTree = ""; }; + 5B27FBF42CC713B5002975BE /* UnknownDappComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnknownDappComponents.swift; sourceTree = ""; }; 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactSupportClient.swift; sourceTree = ""; }; 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactSupportClient+Live.swift"; sourceTree = ""; }; 5B3C48A82C7E190C00DB160D /* AssetRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetRow.swift; sourceTree = ""; }; @@ -2044,7 +2051,6 @@ 8338B9E42AFAB20700D1D8EA /* TransactionFee.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionFee.swift; sourceTree = ""; }; 834B651E2B972E5100B7E1E8 /* NPSSurvey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NPSSurvey.swift; sourceTree = ""; }; 835F196C2B3581C300E0B71D /* UnknownDappComponents+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UnknownDappComponents+View.swift"; sourceTree = ""; }; - 836878602B4551910029C808 /* UnknownDappComponents+Reducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UnknownDappComponents+Reducer.swift"; sourceTree = ""; }; 8370FC5B2B99C780007AD882 /* NPSSurveyClient+Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NPSSurveyClient+Interface.swift"; sourceTree = ""; }; 8381C8AF2BBD2CD400A470B4 /* TokenPriceCientTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenPriceCientTests.swift; sourceTree = ""; }; 8381C8B22BC0619100A470B4 /* RadixConnectMobile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadixConnectMobile.swift; sourceTree = ""; }; @@ -3113,8 +3119,6 @@ children = ( 48CFBCF32ADC10D800E77A5C /* TransactionReviewDapps+View.swift */, 48CFBCF42ADC10D800E77A5C /* TransactionReviewDapps.swift */, - 836878602B4551910029C808 /* UnknownDappComponents+Reducer.swift */, - 835F196C2B3581C300E0B71D /* UnknownDappComponents+View.swift */, ); path = TransactionReviewDapps; sourceTree = ""; @@ -5529,8 +5533,10 @@ 5B27FBE72CC70AAA002975BE /* Helpers */ = { isa = PBXGroup; children = ( - 5B03E3D22CC141C200E10A64 /* InteractionReview+Extra.swift */, + 5B27FBEF2CC70F57002975BE /* Kind.swift */, 5B03E3CE2CC1222D00E10A64 /* DisplayMode.swift */, + 5B03E3D22CC141C200E10A64 /* InteractionReview+Extra.swift */, + 5B27FBED2CC70F2D002975BE /* InteractionReview+Typealias.swift */, ); path = Helpers; sourceTree = ""; @@ -5539,6 +5545,7 @@ isa = PBXGroup; children = ( 5B27FBD82CC67655002975BE /* HeadingView.swift */, + 5B27FBEB2CC70E87002975BE /* ExpandableHeadingView.swift */, 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */, 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */, 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */, @@ -5547,6 +5554,23 @@ path = Components; sourceTree = ""; }; + 5B27FBF12CC710E3002975BE /* Destinations */ = { + isa = PBXGroup; + children = ( + 5B27FBF32CC71100002975BE /* UnknownDappComponents */, + ); + path = Destinations; + sourceTree = ""; + }; + 5B27FBF32CC71100002975BE /* UnknownDappComponents */ = { + isa = PBXGroup; + children = ( + 5B27FBF42CC713B5002975BE /* UnknownDappComponents.swift */, + 835F196C2B3581C300E0B71D /* UnknownDappComponents+View.swift */, + ); + path = UnknownDappComponents; + sourceTree = ""; + }; 5B2A45002BD667FB00AEC8AD /* ContactSupportClient */ = { isa = PBXGroup; children = ( @@ -5620,6 +5644,7 @@ children = ( 5B4A1AC32CC0123300679EE6 /* InteractionReview.swift */, 5B27FBDE2CC6CCA6002975BE /* Sections */, + 5B27FBF12CC710E3002975BE /* Destinations */, 5B27FBE82CC70AC2002975BE /* Components */, 5B27FBE72CC70AAA002975BE /* Helpers */, ); @@ -7233,6 +7258,7 @@ 48CFC6932ADC10DB00E77A5C /* ImportLegacyWalletErrors.swift in Sources */, 48CFC61E2ADC10DA00E77A5C /* LedgerIdentifiable.swift in Sources */, A462B57B2B8210A900C26D20 /* TransactionHistoryClient+Mock.swift in Sources */, + 5B27FBEC2CC70E87002975BE /* ExpandableHeadingView.swift in Sources */, 48CFC4662ADC10DA00E77A5C /* AccountPortfoliosClient+Mock.swift in Sources */, A40815EF2C7E0D08005E65B9 /* ResourceHoldersCollection.swift in Sources */, 48CFC2F02ADC10D900E77A5C /* AddLedgerFactorSource+View.swift in Sources */, @@ -7389,7 +7415,6 @@ 5B45E2FF2BC59780007C4C84 /* SignWithFactorSource.swift in Sources */, 5B3C48C32C874C8D00DB160D /* Dispatch+Extra.swift in Sources */, A40815842C7E0D08005E65B9 /* InvalidTransactionError.swift in Sources */, - 836878612B4551910029C808 /* UnknownDappComponents+Reducer.swift in Sources */, 83823EAA2B72365000827211 /* TokenPriceClient+Interface.swift in Sources */, 48CFC46D2ADC10DA00E77A5C /* PersonasClient+Interface.swift in Sources */, 48CFC2BB2ADC10D900E77A5C /* SelectBackup+Reducer.swift in Sources */, @@ -7477,6 +7502,7 @@ 48CFC3072ADC10D900E77A5C /* DebugUserDefaultsContents.swift in Sources */, A408162A2C7E0D08005E65B9 /* StateNonFungibleDataResponse.swift in Sources */, 48CFC5B72ADC10DA00E77A5C /* Card.swift in Sources */, + 5B27FBF52CC713B6002975BE /* UnknownDappComponents.swift in Sources */, A40815772C7E0D08005E65B9 /* EventsItem.swift in Sources */, 48CFC2BF2ADC10D900E77A5C /* ImportMnemonicsFlowCoordinator.swift in Sources */, 48CFC3632ADC10D900E77A5C /* AssetsView+Reducer.swift in Sources */, @@ -7881,6 +7907,7 @@ 48CFC5DE2ADC10DA00E77A5C /* OnFirstTaskViewModifier.swift in Sources */, 489122782B186F61005F2EEE /* AlternativeRectangularButtonStyle.swift in Sources */, 5B4A1ABF2CC00FB800679EE6 /* PreAuthorizationReview.swift in Sources */, + 5B27FBEE2CC70F2D002975BE /* InteractionReview+Typealias.swift in Sources */, 5B4A1AC02CC00FB800679EE6 /* PreAuthorizationReview+View.swift in Sources */, 48CFC3652ADC10D900E77A5C /* NonFungibleTokenDetails+View.swift in Sources */, 48CFC5C42ADC10DA00E77A5C /* Separator.swift in Sources */, @@ -8057,6 +8084,7 @@ 48CFC2972ADC10D900E77A5C /* AdvancedFeesCustomization.swift in Sources */, A40815CA2C7E0D08005E65B9 /* OptionalNonFungibleIdsCollection.swift in Sources */, 5B9846C22BBD5F7600E814F3 /* SensitiveInfoClient+Live.swift in Sources */, + 5B27FBF02CC70F59002975BE /* Kind.swift in Sources */, A40815C22C7E0D08005E65B9 /* NonFungibleIdType.swift in Sources */, 48CFC4302ADC10DA00E77A5C /* Collection+Extra.swift in Sources */, 48CFC2D62ADC10D900E77A5C /* ChooseAccountsRow.swift in Sources */, diff --git a/RadixWallet/Features/InteractionReview/Components/ExpandableHeadingView.swift b/RadixWallet/Features/InteractionReview/Components/ExpandableHeadingView.swift new file mode 100644 index 0000000000..9a58657e87 --- /dev/null +++ b/RadixWallet/Features/InteractionReview/Components/ExpandableHeadingView.swift @@ -0,0 +1,25 @@ +import SwiftUI + +extension InteractionReview { + struct ExpandableHeadingView: View { + typealias Common = InteractionReview + + let heading: Common.HeadingView + let isExpanded: Bool + let action: () -> Void + + var body: some SwiftUI.View { + Button(action: action) { + HStack(spacing: .small3) { + heading + + Image(asset: isExpanded ? AssetResource.chevronUp : AssetResource.chevronDown) + .renderingMode(.original) + + Spacer(minLength: 0) + } + } + .padding(.trailing, Common.transferLineTrailingPadding + .small3) // padding from the vertical dotted line + } + } +} diff --git a/RadixWallet/Features/InteractionReview/Components/ValidatorsView.swift b/RadixWallet/Features/InteractionReview/Components/ValidatorsView.swift index 1098a0dee3..98abb40ec0 100644 --- a/RadixWallet/Features/InteractionReview/Components/ValidatorsView.swift +++ b/RadixWallet/Features/InteractionReview/Components/ValidatorsView.swift @@ -11,7 +11,7 @@ extension InteractionReview { var body: some SwiftUI.View { VStack(alignment: .leading, spacing: .small2) { - ExpandableTransactionHeading(heading: heading, isExpanded: viewState.isExpanded, action: action) + InteractionReview.ExpandableHeadingView(heading: heading, isExpanded: viewState.isExpanded, action: action) if viewState.isExpanded { VStack(spacing: .small2) { diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewDapps/UnknownDappComponents+View.swift b/RadixWallet/Features/InteractionReview/Destinations/UnknownDappComponents/UnknownDappComponents+View.swift similarity index 59% rename from RadixWallet/Features/TransactionReviewFeature/TransactionReviewDapps/UnknownDappComponents+View.swift rename to RadixWallet/Features/InteractionReview/Destinations/UnknownDappComponents/UnknownDappComponents+View.swift index 5466dadc5d..7540d15369 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewDapps/UnknownDappComponents+View.swift +++ b/RadixWallet/Features/InteractionReview/Destinations/UnknownDappComponents/UnknownDappComponents+View.swift @@ -1,24 +1,19 @@ -extension UnknownDappComponents { - @MainActor +extension InteractionReview.UnknownDappComponents { struct View: SwiftUI.View { - let store: StoreOf - - init(store: StoreOf) { - self.store = store - } + let store: StoreOf var body: some SwiftUI.View { - store.withState { state in - ScrollView { - ForEach(state.addresses, id: \.address) { address in - row(address, heading: state.rowHeading) - } + ScrollView { + ForEach(store.addresses, id: \.address) { address in + row(address, heading: store.rowHeading) } - .radixToolbar(title: state.title, alwaysVisible: false) } + .radixToolbar(title: store.title, alwaysVisible: false) .toolbar { ToolbarItem(placement: .cancellationAction) { - CloseButton { store.send(.view(.closeButtonTapped)) } + CloseButton { + store.send(.view(.closeButtonTapped)) + } } } } diff --git a/RadixWallet/Features/InteractionReview/Destinations/UnknownDappComponents/UnknownDappComponents.swift b/RadixWallet/Features/InteractionReview/Destinations/UnknownDappComponents/UnknownDappComponents.swift new file mode 100644 index 0000000000..38b8986927 --- /dev/null +++ b/RadixWallet/Features/InteractionReview/Destinations/UnknownDappComponents/UnknownDappComponents.swift @@ -0,0 +1,34 @@ +import ComposableArchitecture + +extension InteractionReview { + @Reducer + struct UnknownDappComponents: FeatureReducer, Sendable { + @ObservableState + struct State: Hashable, Sendable { + let title: String + let rowHeading: String + let addresses: [LedgerIdentifiable.Address] + } + + typealias Action = FeatureAction + + enum ViewAction: Sendable { + case closeButtonTapped + } + + @Dependency(\.dismiss) var dismiss + + var body: some ReducerOf { + Reduce(core) + } + + func reduce(into state: inout State, viewAction: ViewAction) -> Effect { + switch viewAction { + case .closeButtonTapped: + .run { _ in + await dismiss() + } + } + } + } +} diff --git a/RadixWallet/Features/InteractionReview/Helpers/InteractionReview+Typealias.swift b/RadixWallet/Features/InteractionReview/Helpers/InteractionReview+Typealias.swift new file mode 100644 index 0000000000..c32e14b65a --- /dev/null +++ b/RadixWallet/Features/InteractionReview/Helpers/InteractionReview+Typealias.swift @@ -0,0 +1,3 @@ +extension InteractionReview { + typealias Transfer = IDResourceBalance +} diff --git a/RadixWallet/Features/InteractionReview/Helpers/Kind.swift b/RadixWallet/Features/InteractionReview/Helpers/Kind.swift new file mode 100644 index 0000000000..421a1f4e77 --- /dev/null +++ b/RadixWallet/Features/InteractionReview/Helpers/Kind.swift @@ -0,0 +1,9 @@ +import Foundation + +// MARK: InteractionReview.Kind +extension InteractionReview { + enum Kind: Sendable, Hashable { + case transaction + case preAuthorization + } +} diff --git a/RadixWallet/Features/InteractionReview/InteractionReview.swift b/RadixWallet/Features/InteractionReview/InteractionReview.swift index b30c7330bd..1753d5312d 100644 --- a/RadixWallet/Features/InteractionReview/InteractionReview.swift +++ b/RadixWallet/Features/InteractionReview/InteractionReview.swift @@ -3,16 +3,3 @@ import SwiftUI // MARK: - InteractionReview /// Namespace to group every component common to `TransactionReview` and `PreAuthorizationReview` enum InteractionReview {} - -// MARK: InteractionReview.Kind -extension InteractionReview { - enum Kind: Sendable, Hashable { - case transaction - case preAuthorization - } -} - -// MARK: InteractionReview.Transfer -extension InteractionReview { - typealias Transfer = IDResourceBalance -} diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index 0b9a1638b0..a6c160d193 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -273,7 +273,7 @@ extension TransactionReview { private func usingDappsSection(isExpanded: Bool) -> some SwiftUI.View { IfLetStore(store.scope(state: \.dAppsUsed) { .child(.dAppsUsed($0)) }) { childStore in VStack(alignment: .leading, spacing: .small2) { - ExpandableTransactionHeading(heading: .usingDapps, isExpanded: isExpanded) { + Common.ExpandableHeadingView(heading: .usingDapps, isExpanded: isExpanded) { store.send(.view(.expandUsingDappsTapped)) } if isExpanded { @@ -287,7 +287,7 @@ extension TransactionReview { private func contributingToPools(isExpanded: Bool) -> some SwiftUI.View { IfLetStore(store.scope(state: \.contributingToPools) { .child(.contributingToPools($0)) }) { childStore in VStack(alignment: .leading, spacing: .small2) { - ExpandableTransactionHeading(heading: .contributingToPools, isExpanded: isExpanded) { + Common.ExpandableHeadingView(heading: .contributingToPools, isExpanded: isExpanded) { store.send(.view(.expandContributingToPoolsTapped)) } if isExpanded { @@ -301,7 +301,7 @@ extension TransactionReview { private func redeemingFromPools(isExpanded: Bool) -> some SwiftUI.View { IfLetStore(store.scope(state: \.redeemingFromPools) { .child(.redeemingFromPools($0)) }) { childStore in VStack(alignment: .leading, spacing: .small2) { - ExpandableTransactionHeading(heading: .redeemingFromPools, isExpanded: isExpanded) { + Common.ExpandableHeadingView(heading: .redeemingFromPools, isExpanded: isExpanded) { store.send(.view(.expandRedeemingFromPoolsTapped)) } if isExpanded { @@ -435,7 +435,7 @@ private extension View { state: /TransactionReview.Destination.State.unknownDappComponents, action: TransactionReview.Destination.Action.unknownDappComponents, content: { - UnknownDappComponents.View(store: $0) + InteractionReview.UnknownDappComponents.View(store: $0) .inNavigationStack .presentationDetents([.medium]) } @@ -506,29 +506,6 @@ private extension View { } } -// MARK: - ExpandableTransactionHeading -struct ExpandableTransactionHeading: View { - typealias Common = InteractionReview - - let heading: Common.HeadingView - let isExpanded: Bool - let action: () -> Void - - var body: some SwiftUI.View { - Button(action: action) { - HStack(spacing: .small3) { - heading - - Image(asset: isExpanded ? AssetResource.chevronUp : AssetResource.chevronDown) - .renderingMode(.original) - - Spacer(minLength: 0) - } - } - .padding(.trailing, Common.transferLineTrailingPadding + .small3) // padding from the vertical dotted line - } -} - // MARK: - TransactionMessageView struct TransactionMessageView: View { let message: String diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift index 782c5e4941..1198463cdb 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift @@ -145,7 +145,7 @@ struct TransactionReview: Sendable, FeatureReducer { case nonFungibleTokenDetails(NonFungibleTokenDetails.State) case poolUnitDetails(PoolUnitDetails.State) case lsuDetails(LSUDetails.State) - case unknownDappComponents(UnknownDappComponents.State) + case unknownDappComponents(Common.UnknownDappComponents.State) case rawTransactionAlert(AlertState) } @@ -159,7 +159,7 @@ struct TransactionReview: Sendable, FeatureReducer { case nonFungibleTokenDetails(NonFungibleTokenDetails.Action) case lsuDetails(LSUDetails.Action) case poolUnitDetails(PoolUnitDetails.Action) - case unknownDappComponents(UnknownDappComponents.Action) + case unknownDappComponents(Common.UnknownDappComponents.Action) case rawTransactionAlert(RawTransactionAlert) enum RawTransactionAlert: Sendable, Equatable { @@ -196,7 +196,7 @@ struct TransactionReview: Sendable, FeatureReducer { LSUDetails() } Scope(state: /State.unknownDappComponents, action: /Action.unknownDappComponents) { - UnknownDappComponents() + Common.UnknownDappComponents() } } } diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewDapps/UnknownDappComponents+Reducer.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReviewDapps/UnknownDappComponents+Reducer.swift deleted file mode 100644 index 35a0404938..0000000000 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewDapps/UnknownDappComponents+Reducer.swift +++ /dev/null @@ -1,22 +0,0 @@ -struct UnknownDappComponents: FeatureReducer, Sendable { - struct State: Hashable, Sendable { - let title: String - let rowHeading: String - let addresses: [LedgerIdentifiable.Address] - } - - enum ViewAction: Sendable { - case closeButtonTapped - } - - @Dependency(\.dismiss) var dismiss - - func reduce(into state: inout State, viewAction: ViewAction) -> Effect { - switch viewAction { - case .closeButtonTapped: - .run { _ in - await dismiss() - } - } - } -} From 58af00314f6d9061e3978d89684cd0ac8d4bd4f3 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 21 Oct 2024 20:22:33 -0300 Subject: [PATCH 17/63] move the last one --- RadixWallet.xcodeproj/project.pbxproj | 32 +++++++++---------- .../Dapps/InteractionReviewDapps+View.swift} | 28 ++++++++-------- .../Dapps/InteractionReviewDapps.swift} | 24 +++++++++----- .../InteractionReview/Sections/Sections.swift | 6 ++-- .../TransactionReview+Sections.swift | 20 ++++++------ .../TransactionReview+View.swift | 6 ++-- .../TransactionReview.swift | 26 ++++++--------- 7 files changed, 71 insertions(+), 71 deletions(-) rename RadixWallet/Features/{TransactionReviewFeature/TransactionReviewDapps/TransactionReviewDapps+View.swift => InteractionReview/Sections/Dapps/InteractionReviewDapps+View.swift} (69%) rename RadixWallet/Features/{TransactionReviewFeature/TransactionReviewDapps/TransactionReviewDapps.swift => InteractionReview/Sections/Dapps/InteractionReviewDapps.swift} (58%) diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index 78a0f8b313..2366875c48 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -142,8 +142,8 @@ 48CFC2972ADC10D900E77A5C /* AdvancedFeesCustomization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCEF2ADC10D800E77A5C /* AdvancedFeesCustomization.swift */; }; 48CFC2982ADC10D900E77A5C /* CustomizeFees+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCF02ADC10D800E77A5C /* CustomizeFees+View.swift */; }; 48CFC2992ADC10D900E77A5C /* CustomizeFees.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCF12ADC10D800E77A5C /* CustomizeFees.swift */; }; - 48CFC29A2ADC10D900E77A5C /* TransactionReviewDapps+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCF32ADC10D800E77A5C /* TransactionReviewDapps+View.swift */; }; - 48CFC29B2ADC10D900E77A5C /* TransactionReviewDapps.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCF42ADC10D800E77A5C /* TransactionReviewDapps.swift */; }; + 48CFC29A2ADC10D900E77A5C /* InteractionReviewDapps+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCF32ADC10D800E77A5C /* InteractionReviewDapps+View.swift */; }; + 48CFC29B2ADC10D900E77A5C /* InteractionReviewDapps.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCF42ADC10D800E77A5C /* InteractionReviewDapps.swift */; }; 48CFC29C2ADC10D900E77A5C /* TransactionReview+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCF52ADC10D800E77A5C /* TransactionReview+View.swift */; }; 48CFC29E2ADC10D900E77A5C /* TransactionReview+DepositExceptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCF82ADC10D800E77A5C /* TransactionReview+DepositExceptionsView.swift */; }; 48CFC29F2ADC10D900E77A5C /* PersonasCoordinator+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCFC2ADC10D800E77A5C /* PersonasCoordinator+View.swift */; }; @@ -1408,8 +1408,8 @@ 48CFBCEF2ADC10D800E77A5C /* AdvancedFeesCustomization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedFeesCustomization.swift; sourceTree = ""; }; 48CFBCF02ADC10D800E77A5C /* CustomizeFees+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CustomizeFees+View.swift"; sourceTree = ""; }; 48CFBCF12ADC10D800E77A5C /* CustomizeFees.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomizeFees.swift; sourceTree = ""; }; - 48CFBCF32ADC10D800E77A5C /* TransactionReviewDapps+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TransactionReviewDapps+View.swift"; sourceTree = ""; }; - 48CFBCF42ADC10D800E77A5C /* TransactionReviewDapps.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionReviewDapps.swift; sourceTree = ""; }; + 48CFBCF32ADC10D800E77A5C /* InteractionReviewDapps+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "InteractionReviewDapps+View.swift"; sourceTree = ""; }; + 48CFBCF42ADC10D800E77A5C /* InteractionReviewDapps.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InteractionReviewDapps.swift; sourceTree = ""; }; 48CFBCF52ADC10D800E77A5C /* TransactionReview+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TransactionReview+View.swift"; sourceTree = ""; }; 48CFBCF82ADC10D800E77A5C /* TransactionReview+DepositExceptionsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TransactionReview+DepositExceptionsView.swift"; sourceTree = ""; }; 48CFBCFC2ADC10D800E77A5C /* PersonasCoordinator+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PersonasCoordinator+View.swift"; sourceTree = ""; }; @@ -3020,7 +3020,6 @@ 48CFBCE12ADC10D800E77A5C /* TransactionReviewRawTransaction */, 48CFBCE72ADC10D800E77A5C /* TransactionReviewNetworkFee */, 48CFBCEA2ADC10D800E77A5C /* CustomizeFees */, - 48CFBCF22ADC10D800E77A5C /* TransactionReviewDapps */, A4B017F32B4BF57B00B42B8E /* TransactionReviewDepositSetting */, 48CFBCF62ADC10D800E77A5C /* TransactionReviewDepositExceptions */, ); @@ -3114,15 +3113,6 @@ path = CustomizeFees; sourceTree = ""; }; - 48CFBCF22ADC10D800E77A5C /* TransactionReviewDapps */ = { - isa = PBXGroup; - children = ( - 48CFBCF32ADC10D800E77A5C /* TransactionReviewDapps+View.swift */, - 48CFBCF42ADC10D800E77A5C /* TransactionReviewDapps.swift */, - ); - path = TransactionReviewDapps; - sourceTree = ""; - }; 48CFBCF62ADC10D800E77A5C /* TransactionReviewDepositExceptions */ = { isa = PBXGroup; children = ( @@ -5526,6 +5516,7 @@ 5B27FBDF2CC6CCBE002975BE /* Sections.swift */, 48CFBCE42ADC10D800E77A5C /* Accounts */, 48CFBCDE2ADC10D800E77A5C /* Proofs */, + 5B27FBF62CC716BC002975BE /* Dapps */, ); path = Sections; sourceTree = ""; @@ -5571,6 +5562,15 @@ path = UnknownDappComponents; sourceTree = ""; }; + 5B27FBF62CC716BC002975BE /* Dapps */ = { + isa = PBXGroup; + children = ( + 48CFBCF42ADC10D800E77A5C /* InteractionReviewDapps.swift */, + 48CFBCF32ADC10D800E77A5C /* InteractionReviewDapps+View.swift */, + ); + path = Dapps; + sourceTree = ""; + }; 5B2A45002BD667FB00AEC8AD /* ContactSupportClient */ = { isa = PBXGroup; children = ( @@ -7728,7 +7728,7 @@ A408155D2C7E0D08005E65B9 /* AccountLockerAddress.swift in Sources */, 48CFC2CC2ADC10D900E77A5C /* FungibleResourceAsset+Reducer.swift in Sources */, A40815B72C7E0D08005E65B9 /* NativeResourceRedemptionValueItem.swift in Sources */, - 48CFC29A2ADC10D900E77A5C /* TransactionReviewDapps+View.swift in Sources */, + 48CFC29A2ADC10D900E77A5C /* InteractionReviewDapps+View.swift in Sources */, 483A3DE62BD2678900055932 /* Stage1MigrateToSargon+FactorSourceCryptoParameters.swift in Sources */, 5B03E3D52CC1487900E10A64 /* TransferLineView.swift in Sources */, 48CFC36B2ADC10D900E77A5C /* FungibleTokenDetails+Reducer.swift in Sources */, @@ -8324,7 +8324,7 @@ 48CFC4672ADC10DA00E77A5C /* AccountPortfoliosClient+Interface.swift in Sources */, 48CFC36A2ADC10D900E77A5C /* FungibleAssetListSection+Reducer.swift in Sources */, 48CFC45A2ADC10DA00E77A5C /* LedgerHardwareWalletClient+Test.swift in Sources */, - 48CFC29B2ADC10D900E77A5C /* TransactionReviewDapps.swift in Sources */, + 48CFC29B2ADC10D900E77A5C /* InteractionReviewDapps.swift in Sources */, 48CFC3532ADC10D900E77A5C /* DappInteractor+ViewModifier.swift in Sources */, 48CFC40C2ADC10DA00E77A5C /* UserDefaults+Dependency+Extension.swift in Sources */, 48CFC2442ADC10D900E77A5C /* ThirdPartyDeposits+Reducer.swift in Sources */, diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewDapps/TransactionReviewDapps+View.swift b/RadixWallet/Features/InteractionReview/Sections/Dapps/InteractionReviewDapps+View.swift similarity index 69% rename from RadixWallet/Features/TransactionReviewFeature/TransactionReviewDapps/TransactionReviewDapps+View.swift rename to RadixWallet/Features/InteractionReview/Sections/Dapps/InteractionReviewDapps+View.swift index a69969fdd7..a2f38b3b7b 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewDapps/TransactionReviewDapps+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Dapps/InteractionReviewDapps+View.swift @@ -1,8 +1,8 @@ import ComposableArchitecture import SwiftUI -extension TransactionReviewDapps.State { - var viewState: TransactionReviewDapps.ViewState { +extension InteractionReviewDapps.State { + var viewState: InteractionReviewDapps.ViewState { var dApps = knownDapps.map(\.knownDapp) if !unknownDapps.isEmpty { dApps.append(.unknown(unknownTitle)) @@ -11,8 +11,8 @@ extension TransactionReviewDapps.State { } } -extension TransactionReview.DappEntity { - fileprivate var knownDapp: TransactionReview.DappView.ViewState { +extension InteractionReview.DappEntity { + fileprivate var knownDapp: InteractionReview.DappView.ViewState { .known( name: metadata.name, thumbnail: metadata.iconURL, @@ -21,17 +21,17 @@ extension TransactionReview.DappEntity { } } -// MARK: - TransactionReviewDapps.View -extension TransactionReviewDapps { +// MARK: - InteractionReviewDapps.View +extension InteractionReviewDapps { struct ViewState: Equatable { - let rows: [TransactionReview.DappView.ViewState] + let rows: [InteractionReview.DappView.ViewState] } @MainActor struct View: SwiftUI.View { - let store: StoreOf + let store: StoreOf - init(store: StoreOf) { + init(store: StoreOf) { self.store = store } @@ -39,7 +39,7 @@ extension TransactionReviewDapps { WithViewStore(store, observe: \.viewState, send: { .view($0) }) { viewStore in VStack(spacing: .small2) { ForEach(viewStore.rows, id: \.self) { rowViewState in - TransactionReview.DappView(viewState: rowViewState) { action in + InteractionReview.DappView(viewState: rowViewState) { action in switch action { case let .knownDappTapped(id): viewStore.send(.dappTapped(id)) @@ -54,16 +54,16 @@ extension TransactionReviewDapps { } } -// MARK: - TransactionReview.DappView -extension TransactionReview { +// MARK: - InteractionReview.DappView +extension InteractionReview { struct DappView: SwiftUI.View { enum ViewState: Hashable { - case known(name: String?, thumbnail: URL?, id: TransactionReview.DappEntity.ID) + case known(name: String?, thumbnail: URL?, id: InteractionReview.DappEntity.ID) case unknown(String) } enum Action { - case knownDappTapped(TransactionReview.DappEntity.ID) + case knownDappTapped(InteractionReview.DappEntity.ID) case unknownComponentsTapped } diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewDapps/TransactionReviewDapps.swift b/RadixWallet/Features/InteractionReview/Sections/Dapps/InteractionReviewDapps.swift similarity index 58% rename from RadixWallet/Features/TransactionReviewFeature/TransactionReviewDapps/TransactionReviewDapps.swift rename to RadixWallet/Features/InteractionReview/Sections/Dapps/InteractionReviewDapps.swift index 830ea690f1..ff325bf23f 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewDapps/TransactionReviewDapps.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Dapps/InteractionReviewDapps.swift @@ -2,18 +2,18 @@ import ComposableArchitecture import Sargon import SwiftUI -typealias TransactionReviewPools = TransactionReviewDapps -typealias TransactionReviewDappsUsed = TransactionReviewDapps +typealias InteractionReviewPools = InteractionReviewDapps +typealias InteractionReviewDappsUsed = InteractionReviewDapps -// MARK: - TransactionReviewDapps -struct TransactionReviewDapps: Sendable, FeatureReducer { +// MARK: - InteractionReviewDapps +struct InteractionReviewDapps: Sendable, FeatureReducer { struct State: Sendable, Hashable { - var knownDapps: IdentifiedArrayOf + var knownDapps: IdentifiedArrayOf var unknownDapps: IdentifiedArrayOf var isExpanded: Bool = true let unknownTitle: String - init(knownDapps: IdentifiedArrayOf, unknownDapps: IdentifiedArrayOf, unknownTitle: (Int) -> String) { + init(knownDapps: IdentifiedArrayOf, unknownDapps: IdentifiedArrayOf, unknownTitle: (Int) -> String) { self.knownDapps = knownDapps self.unknownDapps = unknownDapps self.unknownTitle = unknownTitle(unknownDapps.count) @@ -21,12 +21,12 @@ struct TransactionReviewDapps: Sendable, FeatureRe } enum ViewAction: Sendable, Equatable { - case dappTapped(TransactionReview.DappEntity.ID) + case dappTapped(InteractionReview.DappEntity.ID) case unknownsTapped } enum DelegateAction: Sendable, Equatable { - case openDapp(TransactionReview.DappEntity.ID) + case openDapp(InteractionReview.DappEntity.ID) case openUnknownAddresses(IdentifiedArrayOf) } @@ -42,3 +42,11 @@ struct TransactionReviewDapps: Sendable, FeatureRe } } } + +// MARK: - InteractionReview.DappEntity +extension InteractionReview { + struct DappEntity: Sendable, Identifiable, Hashable { + let id: DappDefinitionAddress + let metadata: OnLedgerEntity.Metadata + } +} diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections.swift b/RadixWallet/Features/InteractionReview/Sections/Sections.swift index 48b76aa4c8..e127d7ab32 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections.swift @@ -3,11 +3,11 @@ import Foundation extension InteractionReview { struct Sections: Sendable, Hashable { var withdrawals: Accounts.State? = nil - var dAppsUsed: TransactionReviewDappsUsed.State? = nil + var dAppsUsed: InteractionReviewDappsUsed.State? = nil var deposits: Accounts.State? = nil - var contributingToPools: TransactionReviewPools.State? = nil - var redeemingFromPools: TransactionReviewPools.State? = nil + var contributingToPools: InteractionReviewPools.State? = nil + var redeemingFromPools: InteractionReviewPools.State? = nil var stakingToValidators: InteractionReview.ValidatorsState? = nil var unstakingFromValidators: InteractionReview.ValidatorsState? = nil diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift index ebba214ce6..b164f826e1 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift @@ -66,7 +66,7 @@ extension TransactionReview { } } - let dAppsUsed: TransactionReviewDappsUsed.State? = try await extractDapps( + let dAppsUsed = try await extractDapps( addresses: dappAddresses, unknownTitle: L10n.TransactionReview.unknownComponents ) @@ -99,7 +99,7 @@ extension TransactionReview { let perPoolUnitDapps = try perPoolUnitDapps(dApps, poolInteractions: poolContributions) // Extract Contributing to Pools section - let pools: TransactionReviewPools.State? = try await extractDapps(dApps, unknownTitle: L10n.TransactionReview.unknownPools) + let pools: InteractionReviewPools.State? = try await extractDapps(dApps, unknownTitle: L10n.TransactionReview.unknownPools) // Extract Withdrawals section let withdrawals = try await extractWithdrawals( @@ -140,7 +140,7 @@ extension TransactionReview { let perPoolUnitDapps = try perPoolUnitDapps(dApps, poolInteractions: poolRedemptions) // Extract Contributing to Pools section - let pools: TransactionReviewPools.State? = try await extractDapps(dApps, unknownTitle: L10n.TransactionReview.unknownPools) + let pools: InteractionReviewPools.State? = try await extractDapps(dApps, unknownTitle: L10n.TransactionReview.unknownPools) // Extract Withdrawals section, passing in poolRedemptions so that withdrawn pool units can be updated let withdrawals = try await extractWithdrawals( @@ -304,15 +304,15 @@ extension TransactionReview { private func extractDapps( addresses: [Address], unknownTitle: (Int) -> String - ) async throws -> TransactionReviewDapps.State? { + ) async throws -> InteractionReviewDapps.State? { let dApps = await extractDappEntities(addresses) return try await extractDapps(dApps, unknownTitle: unknownTitle) } private func extractDapps( - _ dAppEntities: [(address: Address, entity: DappEntity?)], + _ dAppEntities: [(address: Address, entity: InteractionReview.DappEntity?)], unknownTitle: (Int) -> String - ) async throws -> TransactionReviewDapps.State? { + ) async throws -> InteractionReviewDapps.State? { let knownDapps = dAppEntities.compactMap(\.entity).asIdentified() let unknownDapps = try dAppEntities.filter { $0.entity == nil } .map { try $0.address.asSpecific(type: A.self) }.asIdentified() @@ -322,16 +322,16 @@ extension TransactionReview { return .init(knownDapps: knownDapps, unknownDapps: unknownDapps, unknownTitle: unknownTitle) } - private func extractDappEntities(_ addresses: [Address]) async -> [(address: Address, entity: DappEntity?)] { + private func extractDappEntities(_ addresses: [Address]) async -> [(address: Address, entity: InteractionReview.DappEntity?)] { await addresses.asyncMap { await (address: $0, entity: try? extractDappEntity($0.asGeneral)) } } - private func extractDappEntity(_ entity: Address) async throws -> DappEntity { + private func extractDappEntity(_ entity: Address) async throws -> InteractionReview.DappEntity { let dAppDefinitionAddress = try await onLedgerEntitiesClient.getDappDefinitionAddress(entity) let metadata = try await onLedgerEntitiesClient.getDappMetadata(dAppDefinitionAddress, validatingDappEntity: entity) - return DappEntity(id: dAppDefinitionAddress, metadata: metadata) + return .init(id: dAppDefinitionAddress, metadata: metadata) } private func exctractProofs(_ accountProofs: [ResourceSpecifier]) async throws -> Common.Proofs.State? { @@ -558,7 +558,7 @@ extension TransactionReview { } private func perPoolUnitDapps( - _ dappEntities: [(address: Address, entity: TransactionReview.DappEntity?)], + _ dappEntities: [(address: Address, entity: InteractionReview.DappEntity?)], poolInteractions: [some TrackedPoolInteraction] ) throws -> ResourceAssociatedDapps { try Dictionary(keysWithValues: dappEntities.compactMap { data -> (ResourceAddress, OnLedgerEntity.Metadata)? in diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index a6c160d193..a9351587a4 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -277,7 +277,7 @@ extension TransactionReview { store.send(.view(.expandUsingDappsTapped)) } if isExpanded { - TransactionReviewDappsUsed.View(store: childStore) + InteractionReviewDappsUsed.View(store: childStore) .transition(.opacity.combined(with: .scale(scale: 0.95))) } } @@ -291,7 +291,7 @@ extension TransactionReview { store.send(.view(.expandContributingToPoolsTapped)) } if isExpanded { - TransactionReviewPools.View(store: childStore) + InteractionReviewPools.View(store: childStore) .transition(.opacity.combined(with: .scale(scale: 0.95))) } } @@ -305,7 +305,7 @@ extension TransactionReview { store.send(.view(.expandRedeemingFromPoolsTapped)) } if isExpanded { - TransactionReviewPools.View(store: childStore) + InteractionReviewPools.View(store: childStore) .transition(.opacity.combined(with: .scale(scale: 0.95))) } } diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift index 1198463cdb..9f7664204a 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift @@ -22,9 +22,9 @@ struct TransactionReview: Sendable, FeatureReducer { var reviewedTransaction: ReviewedTransaction? = nil var withdrawals: Common.Accounts.State? = nil - var dAppsUsed: TransactionReviewDappsUsed.State? = nil - var contributingToPools: TransactionReviewPools.State? = nil - var redeemingFromPools: TransactionReviewPools.State? = nil + var dAppsUsed: InteractionReviewDappsUsed.State? = nil + var contributingToPools: InteractionReviewPools.State? = nil + var redeemingFromPools: InteractionReviewPools.State? = nil var deposits: Common.Accounts.State? = nil var stakingToValidators: Common.ValidatorsState? = nil @@ -112,9 +112,9 @@ struct TransactionReview: Sendable, FeatureReducer { enum ChildAction: Sendable, Equatable { case withdrawals(Common.Accounts.Action) case deposits(Common.Accounts.Action) - case dAppsUsed(TransactionReviewDappsUsed.Action) - case contributingToPools(TransactionReviewPools.Action) - case redeemingFromPools(TransactionReviewPools.Action) + case dAppsUsed(InteractionReviewDappsUsed.Action) + case contributingToPools(InteractionReviewPools.Action) + case redeemingFromPools(InteractionReviewPools.Action) case proofs(Common.Proofs.Action) case networkFee(TransactionReviewNetworkFee.Action) } @@ -221,13 +221,13 @@ struct TransactionReview: Sendable, FeatureReducer { Common.Accounts() } .ifLet(\.dAppsUsed, action: /Action.child .. ChildAction.dAppsUsed) { - TransactionReviewDappsUsed() + InteractionReviewDappsUsed() } .ifLet(\.contributingToPools, action: /Action.child .. ChildAction.contributingToPools) { - TransactionReviewPools() + InteractionReviewPools() } .ifLet(\.redeemingFromPools, action: /Action.child .. ChildAction.redeemingFromPools) { - TransactionReviewPools() + InteractionReviewPools() } .ifLet(\.withdrawals, action: /Action.child .. ChildAction.withdrawals) { Common.Accounts() @@ -779,14 +779,6 @@ extension TransactionReview { } } -// MARK: - TransactionReview.DappEntity -extension TransactionReview { - struct DappEntity: Sendable, Identifiable, Hashable { - let id: DappDefinitionAddress - let metadata: OnLedgerEntity.Metadata - } -} - extension ResourceBalance { /// The guarantee, for a fungible resource var fungibleGuarantee: TransactionGuarantee? { From 68fec2b1279f2194f14a2cc0bfc89ae78f61638e Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 21 Oct 2024 20:22:55 -0300 Subject: [PATCH 18/63] show on Home --- .../HomeFeature/Coordinator/Home+View.swift | 10 ++++++++++ .../Features/HomeFeature/Coordinator/Home.swift | 14 +++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/RadixWallet/Features/HomeFeature/Coordinator/Home+View.swift b/RadixWallet/Features/HomeFeature/Coordinator/Home+View.swift index e2bcb2f939..24fee04bf1 100644 --- a/RadixWallet/Features/HomeFeature/Coordinator/Home+View.swift +++ b/RadixWallet/Features/HomeFeature/Coordinator/Home+View.swift @@ -118,6 +118,7 @@ private extension View { .relinkConnector(with: destinationStore) .securityCenter(with: destinationStore) .p2pLinks(with: destinationStore) + .preAuth(with: destinationStore, store: store) } private func accountDetails(with destinationStore: PresentationStoreOf) -> some View { @@ -159,6 +160,15 @@ private extension View { P2PLinksFeature.View(store: $0) } } + + private func preAuth(with destinationStore: PresentationStoreOf, store: StoreOf) -> some View { + fullScreenCover(store: destinationStore.scope(state: \.preAuth, action: \.preAuth)) { + PreAuthorizationReview.View(store: $0) + .withNavigationBar { + store.send(.view(.dismissPreAuth)) + } + } + } } extension View { diff --git a/RadixWallet/Features/HomeFeature/Coordinator/Home.swift b/RadixWallet/Features/HomeFeature/Coordinator/Home.swift index 9afbe651ed..5021226d42 100644 --- a/RadixWallet/Features/HomeFeature/Coordinator/Home.swift +++ b/RadixWallet/Features/HomeFeature/Coordinator/Home.swift @@ -55,6 +55,7 @@ struct Home: Sendable, FeatureReducer { case createAccountButtonTapped case settingsButtonTapped case showFiatWorthToggled + case dismissPreAuth } enum InternalAction: Sendable, Equatable { @@ -88,6 +89,7 @@ struct Home: Sendable, FeatureReducer { case relinkConnector(NewConnection.State) case securityCenter(SecurityCenter.State) case p2pLinks(P2PLinksFeature.State) + case preAuth(PreAuthorizationReview.State) } @CasePathable @@ -99,6 +101,7 @@ struct Home: Sendable, FeatureReducer { case relinkConnector(NewConnection.Action) case securityCenter(SecurityCenter.Action) case p2pLinks(P2PLinksFeature.Action) + case preAuth(PreAuthorizationReview.Action) enum AcknowledgeJailbreakAlert: Sendable, Hashable {} } @@ -122,6 +125,9 @@ struct Home: Sendable, FeatureReducer { Scope(state: \.p2pLinks, action: \.p2pLinks) { P2PLinksFeature() } + Scope(state: \.preAuth, action: \.preAuth) { + PreAuthorizationReview() + } } } @@ -209,12 +215,18 @@ struct Home: Sendable, FeatureReducer { return fetchAccountPortfolios(state) case .settingsButtonTapped: - return .send(.delegate(.displaySettings)) + state.destination = .preAuth(.init()) + return .none +// return .send(.delegate(.displaySettings)) case .showFiatWorthToggled: return .run { _ in try await appPreferencesClient.toggleIsCurrencyAmountVisible() } + + case .dismissPreAuth: + state.destination = nil + return .none } } From 4287c70be81a75026d8ba1e7e45bf6727d5a6021 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 22 Oct 2024 10:48:12 -0300 Subject: [PATCH 19/63] InteractionReviewDapps use ObservableState --- .../Dapps/InteractionReviewDapps+View.swift | 57 ++++++++----------- .../Dapps/InteractionReviewDapps.swift | 8 ++- 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/RadixWallet/Features/InteractionReview/Sections/Dapps/InteractionReviewDapps+View.swift b/RadixWallet/Features/InteractionReview/Sections/Dapps/InteractionReviewDapps+View.swift index a2f38b3b7b..d9c8509933 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Dapps/InteractionReviewDapps+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Dapps/InteractionReviewDapps+View.swift @@ -1,50 +1,21 @@ import ComposableArchitecture import SwiftUI -extension InteractionReviewDapps.State { - var viewState: InteractionReviewDapps.ViewState { - var dApps = knownDapps.map(\.knownDapp) - if !unknownDapps.isEmpty { - dApps.append(.unknown(unknownTitle)) - } - return .init(rows: dApps) - } -} - -extension InteractionReview.DappEntity { - fileprivate var knownDapp: InteractionReview.DappView.ViewState { - .known( - name: metadata.name, - thumbnail: metadata.iconURL, - id: id - ) - } -} - // MARK: - InteractionReviewDapps.View extension InteractionReviewDapps { - struct ViewState: Equatable { - let rows: [InteractionReview.DappView.ViewState] - } - - @MainActor struct View: SwiftUI.View { let store: StoreOf - init(store: StoreOf) { - self.store = store - } - var body: some SwiftUI.View { - WithViewStore(store, observe: \.viewState, send: { .view($0) }) { viewStore in + WithPerceptionTracking { VStack(spacing: .small2) { - ForEach(viewStore.rows, id: \.self) { rowViewState in + ForEach(store.rows, id: \.self) { rowViewState in InteractionReview.DappView(viewState: rowViewState) { action in switch action { case let .knownDappTapped(id): - viewStore.send(.dappTapped(id)) + store.send(.view(.dappTapped(id))) case .unknownComponentsTapped: - viewStore.send(.unknownsTapped) + store.send(.view(.unknownsTapped)) } } } @@ -54,6 +25,26 @@ extension InteractionReviewDapps { } } +extension InteractionReviewDapps.State { + var rows: [InteractionReview.DappView.ViewState] { + var dApps = knownDapps.map(\.knownDapp) + if !unknownDapps.isEmpty { + dApps.append(.unknown(unknownTitle)) + } + return dApps + } +} + +extension InteractionReview.DappEntity { + fileprivate var knownDapp: InteractionReview.DappView.ViewState { + .known( + name: metadata.name, + thumbnail: metadata.iconURL, + id: id + ) + } +} + // MARK: - InteractionReview.DappView extension InteractionReview { struct DappView: SwiftUI.View { diff --git a/RadixWallet/Features/InteractionReview/Sections/Dapps/InteractionReviewDapps.swift b/RadixWallet/Features/InteractionReview/Sections/Dapps/InteractionReviewDapps.swift index ff325bf23f..f260f7ff54 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Dapps/InteractionReviewDapps.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Dapps/InteractionReviewDapps.swift @@ -6,7 +6,9 @@ typealias InteractionReviewPools = InteractionReviewDapps typealias InteractionReviewDappsUsed = InteractionReviewDapps // MARK: - InteractionReviewDapps +@Reducer struct InteractionReviewDapps: Sendable, FeatureReducer { + @ObservableState struct State: Sendable, Hashable { var knownDapps: IdentifiedArrayOf var unknownDapps: IdentifiedArrayOf @@ -20,6 +22,8 @@ struct InteractionReviewDapps: Sendable, FeatureRe } } + typealias Action = FeatureAction + enum ViewAction: Sendable, Equatable { case dappTapped(InteractionReview.DappEntity.ID) case unknownsTapped @@ -30,7 +34,9 @@ struct InteractionReviewDapps: Sendable, FeatureRe case openUnknownAddresses(IdentifiedArrayOf) } - init() {} + var body: some ReducerOf { + Reduce(core) + } func reduce(into state: inout State, viewAction: ViewAction) -> Effect { switch viewAction { From 349c7dcbb17eb9f4d4aa3af11fe5de29fca10c00 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 22 Oct 2024 11:53:12 -0300 Subject: [PATCH 20/63] wip middle sections --- RadixWallet.xcodeproj/project.pbxproj | 20 +- .../MiddleSections+ExecutionSummary.swift | 649 ++++++++++++++++++ .../Sections/MiddleSections+Simulate.swift} | 2 +- .../Sections/MiddleSections+View.swift | 201 ++++++ .../Sections/MiddleSections.swift | 283 ++++++++ .../PreAuthorizationReview+View.swift | 33 +- .../PreAuthorizationReview.swift | 45 +- .../TransactionReview+View.swift | 42 +- .../TransactionReview.swift | 35 +- 9 files changed, 1197 insertions(+), 113 deletions(-) create mode 100644 RadixWallet/Features/InteractionReview/Sections/MiddleSections+ExecutionSummary.swift rename RadixWallet/Features/{PreAuthorizationReview/PreAuthorizationReview+Sections.swift => InteractionReview/Sections/MiddleSections+Simulate.swift} (96%) create mode 100644 RadixWallet/Features/InteractionReview/Sections/MiddleSections+View.swift create mode 100644 RadixWallet/Features/InteractionReview/Sections/MiddleSections.swift diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index 2366875c48..0edbf1c498 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -723,12 +723,15 @@ 5B272DDB2C36E9D300B74F1F /* AppEventsClient+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B272DDA2C36E9D300B74F1F /* AppEventsClient+Test.swift */; }; 5B27FBD92CC67655002975BE /* HeadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBD82CC67655002975BE /* HeadingView.swift */; }; 5B27FBE02CC6CCBE002975BE /* Sections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBDF2CC6CCBE002975BE /* Sections.swift */; }; - 5B27FBE62CC700F4002975BE /* PreAuthorizationReview+Sections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBE52CC700E5002975BE /* PreAuthorizationReview+Sections.swift */; }; 5B27FBEA2CC70CA1002975BE /* ValidatorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBE92CC70C9D002975BE /* ValidatorsView.swift */; }; 5B27FBEC2CC70E87002975BE /* ExpandableHeadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBEB2CC70E87002975BE /* ExpandableHeadingView.swift */; }; 5B27FBEE2CC70F2D002975BE /* InteractionReview+Typealias.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBED2CC70F2D002975BE /* InteractionReview+Typealias.swift */; }; 5B27FBF02CC70F59002975BE /* Kind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBEF2CC70F57002975BE /* Kind.swift */; }; 5B27FBF52CC713B6002975BE /* UnknownDappComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBF42CC713B5002975BE /* UnknownDappComponents.swift */; }; + 5B27FBFD2CC7E6C1002975BE /* MiddleSections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBFB2CC7E6C1002975BE /* MiddleSections.swift */; }; + 5B27FBFE2CC7E6C1002975BE /* MiddleSections+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBFC2CC7E6C1002975BE /* MiddleSections+View.swift */; }; + 5B27FC002CC7E783002975BE /* MiddleSections+ExecutionSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBFF2CC7E77B002975BE /* MiddleSections+ExecutionSummary.swift */; }; + 5B27FC022CC7ECC9002975BE /* MiddleSections+Simulate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FC012CC7ECC2002975BE /* MiddleSections+Simulate.swift */; }; 5B2A45022BD6680400AEC8AD /* ContactSupportClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */; }; 5B2A45042BD6689100AEC8AD /* ContactSupportClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */; }; 5B3C48A92C7E190C00DB160D /* AssetRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B3C48A82C7E190C00DB160D /* AssetRow.swift */; }; @@ -1958,12 +1961,15 @@ 5B272DDA2C36E9D300B74F1F /* AppEventsClient+Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppEventsClient+Test.swift"; sourceTree = ""; }; 5B27FBD82CC67655002975BE /* HeadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadingView.swift; sourceTree = ""; }; 5B27FBDF2CC6CCBE002975BE /* Sections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sections.swift; sourceTree = ""; }; - 5B27FBE52CC700E5002975BE /* PreAuthorizationReview+Sections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationReview+Sections.swift"; sourceTree = ""; }; 5B27FBE92CC70C9D002975BE /* ValidatorsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorsView.swift; sourceTree = ""; }; 5B27FBEB2CC70E87002975BE /* ExpandableHeadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableHeadingView.swift; sourceTree = ""; }; 5B27FBED2CC70F2D002975BE /* InteractionReview+Typealias.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InteractionReview+Typealias.swift"; sourceTree = ""; }; 5B27FBEF2CC70F57002975BE /* Kind.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Kind.swift; sourceTree = ""; }; 5B27FBF42CC713B5002975BE /* UnknownDappComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnknownDappComponents.swift; sourceTree = ""; }; + 5B27FBFB2CC7E6C1002975BE /* MiddleSections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MiddleSections.swift; sourceTree = ""; }; + 5B27FBFC2CC7E6C1002975BE /* MiddleSections+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MiddleSections+View.swift"; sourceTree = ""; }; + 5B27FBFF2CC7E77B002975BE /* MiddleSections+ExecutionSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MiddleSections+ExecutionSummary.swift"; sourceTree = ""; }; + 5B27FC012CC7ECC2002975BE /* MiddleSections+Simulate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MiddleSections+Simulate.swift"; sourceTree = ""; }; 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactSupportClient.swift; sourceTree = ""; }; 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactSupportClient+Live.swift"; sourceTree = ""; }; 5B3C48A82C7E190C00DB160D /* AssetRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetRow.swift; sourceTree = ""; }; @@ -5514,6 +5520,10 @@ isa = PBXGroup; children = ( 5B27FBDF2CC6CCBE002975BE /* Sections.swift */, + 5B27FBFB2CC7E6C1002975BE /* MiddleSections.swift */, + 5B27FBFC2CC7E6C1002975BE /* MiddleSections+View.swift */, + 5B27FBFF2CC7E77B002975BE /* MiddleSections+ExecutionSummary.swift */, + 5B27FC012CC7ECC2002975BE /* MiddleSections+Simulate.swift */, 48CFBCE42ADC10D800E77A5C /* Accounts */, 48CFBCDE2ADC10D800E77A5C /* Proofs */, 5B27FBF62CC716BC002975BE /* Dapps */, @@ -5634,7 +5644,6 @@ children = ( 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */, 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */, - 5B27FBE52CC700E5002975BE /* PreAuthorizationReview+Sections.swift */, ); path = PreAuthorizationReview; sourceTree = ""; @@ -7398,6 +7407,7 @@ 48CFC2A42ADC10D900E77A5C /* PersonaList+Reducer.swift in Sources */, 48CFC5AA2ADC10DA00E77A5C /* PrimaryRectangularButtonStyle.swift in Sources */, 48CFC29F2ADC10D900E77A5C /* PersonasCoordinator+View.swift in Sources */, + 5B27FC002CC7E783002975BE /* MiddleSections+ExecutionSummary.swift in Sources */, 48CFC43E2ADC10DA00E77A5C /* FactorSourcesClient+Interface.swift in Sources */, 48CFC4062ADC10DA00E77A5C /* JSONValue.swift in Sources */, 48CFC5812ADC10DA00E77A5C /* URLFormatterClient+Test.swift in Sources */, @@ -7961,6 +7971,8 @@ 48CFC4182ADC10DA00E77A5C /* IdentifiedArrayOf+Extensions.swift in Sources */, 48CFC3EB2ADC10D900E77A5C /* RTCClients.swift in Sources */, 48CFC4592ADC10DA00E77A5C /* LedgerHardwareWalletClient+Interface.swift in Sources */, + 5B27FBFD2CC7E6C1002975BE /* MiddleSections.swift in Sources */, + 5B27FBFE2CC7E6C1002975BE /* MiddleSections+View.swift in Sources */, E6F460132BDBE56800B122DB /* Stage2MigrateToSargon+RadixConnectModels+Logic.swift in Sources */, 4841614D2BCAD3D400D2B644 /* Stage1MigrateToSargon+MnemonicWithPassphrase.swift in Sources */, 48CFC5A82ADC10DA00E77A5C /* URLButtonStyle.swift in Sources */, @@ -8066,7 +8078,6 @@ E7B7A0FD2BBBFB6100EEE900 /* HeaderListViewContainer.swift in Sources */, 48CFC3FA2ADC10D900E77A5C /* SignalingClient.swift in Sources */, 4813B0012BCA48CE0046BCAD /* Stage2MigrateToSargon+ProfileNetwork.swift in Sources */, - 5B27FBE62CC700F4002975BE /* PreAuthorizationReview+Sections.swift in Sources */, A40816332C7E0D08005E65B9 /* StatePackageCodePageRequest.swift in Sources */, 48CFC3692ADC10D900E77A5C /* NonFungibleAssetList+Reducer.swift in Sources */, 48CFC2752ADC10D900E77A5C /* Main+View.swift in Sources */, @@ -8216,6 +8227,7 @@ 48AF19CE2BB71C1600796130 /* IntoSargon+Bridge.swift in Sources */, 5B9846C02BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift in Sources */, 48CFC3492ADC10D900E77A5C /* PersonaDataPermissionBox.swift in Sources */, + 5B27FC022CC7ECC9002975BE /* MiddleSections+Simulate.swift in Sources */, A408164E2C7E0D08005E65B9 /* TransactionStatus.swift in Sources */, 5BBC43A92BBAC6B0005747B1 /* AppTextEditor.swift in Sources */, A41266F12B15579E00EA38E9 /* ManualAccountRecoverySeedPhrase+View.swift in Sources */, diff --git a/RadixWallet/Features/InteractionReview/Sections/MiddleSections+ExecutionSummary.swift b/RadixWallet/Features/InteractionReview/Sections/MiddleSections+ExecutionSummary.swift new file mode 100644 index 0000000000..4c599c815c --- /dev/null +++ b/RadixWallet/Features/InteractionReview/Sections/MiddleSections+ExecutionSummary.swift @@ -0,0 +1,649 @@ +extension InteractionReview.MiddleSections { + // Either the resource from ledger or metadata extracted from the TX manifest + typealias ResourceInfo = Either + typealias ResourcesInfo = [ResourceAddress: ResourceInfo] + typealias ResourceAssociatedDapps = [ResourceAddress: OnLedgerEntity.Metadata] + + func sections(for summary: ExecutionSummary, networkID: NetworkID) async throws -> Common.Sections? { + let allWithdrawAddresses = summary.withdrawals.values.flatMap { $0 }.map(\.resourceAddress) + let allDepositAddresses = summary.deposits.values.flatMap { $0 }.map(\.resourceAddress) + + // Pre-populate with all resource addresses from withdraw and deposit. + let allAddresses: IdentifiedArrayOf = Array((allWithdrawAddresses + allDepositAddresses).uniqued()).asIdentified() + + func resourcesInfo(_ resourceAddresses: [ResourceAddress]) async throws -> ResourcesInfo { + var newlyCreatedMetadata = try Dictionary( + keysWithValues: resourceAddresses.compactMap { resourceAddress in + summary.newEntities.metadata[resourceAddress].map { + ( + resourceAddress, + ResourceInfo.right(OnLedgerEntity.Metadata(newlyCreated: $0)) + ) + } + } + ) + + let existingResources = resourceAddresses.filter { + newlyCreatedMetadata[$0] == nil + } + + let existingResourceDetails = try await onLedgerEntitiesClient.getResources(existingResources) + .reduce(into: ResourcesInfo()) { partialResult, next in + partialResult[next.resourceAddress] = .left(next) + } + + newlyCreatedMetadata.append(contentsOf: existingResourceDetails) + + return newlyCreatedMetadata + } + + switch summary.detailedManifestClass { + case nil: + return nil + + case .general, .transfer: + if summary.detailedManifestClass == .general { + guard !summary.deposits.isEmpty || !summary.withdrawals.isEmpty else { return nil } + } + + let resourcesInfo = try await resourcesInfo(allAddresses.elements) + let withdrawals = try await extractWithdrawals( + accountWithdraws: summary.withdrawals, + newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, + entities: resourcesInfo, + networkID: networkID + ) + + let dappAddresses = summary.encounteredAddresses.compactMap { + switch $0 { + case let .component(componentAddress): + componentAddress.isGlobal ? componentAddress.asGeneral : nil + case let .locker(lockerAddress): + lockerAddress.asGeneral + } + } + + let dAppsUsed = try await extractDapps( + addresses: dappAddresses, + unknownTitle: L10n.TransactionReview.unknownComponents + ) + + let deposits = try await extractDeposits( + accountDeposits: summary.deposits, + newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, + entities: resourcesInfo, + networkID: networkID + ) + + let proofs = try await exctractProofs(summary.presentedProofs) + + return Common.Sections( + withdrawals: withdrawals, + dAppsUsed: dAppsUsed, + deposits: deposits, + proofs: proofs + ) + + case let .poolContribution(poolAddresses, poolContributions): + // All resources that are part of the pool + let resourceAddresses = poolContributions.flatMap { Array($0.contributedResources.keys) } + + let allAddresses = allAddresses + resourceAddresses.asIdentified() + let resourcesInfo = try await resourcesInfo(allAddresses.elements) + + let dApps = await extractDappEntities(poolAddresses.map(\.asGeneral)) + + let perPoolUnitDapps = try perPoolUnitDapps(dApps, poolInteractions: poolContributions) + + // Extract Contributing to Pools section + let pools: InteractionReviewPools.State? = try await extractDapps(dApps, unknownTitle: L10n.TransactionReview.unknownPools) + + // Extract Withdrawals section + let withdrawals = try await extractWithdrawals( + accountWithdraws: summary.withdrawals, + newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, + entities: resourcesInfo, + resourceAssociatedDapps: perPoolUnitDapps, + networkID: networkID + ) + + // Extract Deposits section, passing in poolcontributions so that pool units can be updated + let deposits = try await extractDeposits( + accountDeposits: summary.deposits, + newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, + poolContributions: poolContributions.aggregated, + entities: resourcesInfo, + resourceAssociatedDapps: perPoolUnitDapps, + networkID: networkID + ) + + return Common.Sections( + withdrawals: withdrawals, + deposits: deposits, + contributingToPools: pools + ) + + case let .poolRedemption(poolAddresses, poolRedemptions): + // All resources that are part of the pool + let resourceAddresses = poolRedemptions.flatMap { + Array($0.redeemedResources.keys) + } + + let allAddresses = allAddresses + resourceAddresses.asIdentified() + let resourcesInfo = try await resourcesInfo(allAddresses.elements) + + let dApps = await extractDappEntities(poolAddresses.map(\.asGeneral)) + + let perPoolUnitDapps = try perPoolUnitDapps(dApps, poolInteractions: poolRedemptions) + + // Extract Contributing to Pools section + let pools: InteractionReviewPools.State? = try await extractDapps(dApps, unknownTitle: L10n.TransactionReview.unknownPools) + + // Extract Withdrawals section, passing in poolRedemptions so that withdrawn pool units can be updated + let withdrawals = try await extractWithdrawals( + accountWithdraws: summary.withdrawals, + newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, + poolRedemptions: poolRedemptions.aggregated, + entities: resourcesInfo, + resourceAssociatedDapps: perPoolUnitDapps, + networkID: networkID + ) + + // Extract Deposits section + let deposits = try await extractDeposits( + accountDeposits: summary.deposits, + newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, + entities: resourcesInfo, + resourceAssociatedDapps: perPoolUnitDapps, + networkID: networkID + ) + + return Common.Sections( + withdrawals: withdrawals, + deposits: deposits, + redeemingFromPools: pools + ) + + case let .validatorStake(validatorAddresses: validatorAddresses, validatorStakes: validatorStakes): + let resourcesInfo = try await resourcesInfo(allAddresses.elements) + + let withdrawals = try await extractWithdrawals( + accountWithdraws: summary.withdrawals, + newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, + entities: resourcesInfo, + networkID: networkID + ) + + // Extract validators + let stakingToValidators = try await extractValidators(for: validatorAddresses) + + // Extract Deposits section + let deposits = try await extractDeposits( + accountDeposits: summary.deposits, + newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, + validatorStakes: validatorStakes.aggregated, + entities: resourcesInfo, + networkID: networkID + ) + + return Common.Sections( + withdrawals: withdrawals, + deposits: deposits, + stakingToValidators: stakingToValidators + ) + + case let .validatorUnstake(validatorAddresses, claimsNonFungibleData): + let resourcesInfo = try await resourcesInfo(allAddresses.elements) + + let withdrawals = try await extractWithdrawals( + accountWithdraws: summary.withdrawals, + newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, + entities: resourcesInfo, + networkID: networkID + ) + + // Extract validators + let unstakingFromValidators = try await extractValidators(for: validatorAddresses) + + // Extract Deposits section + let deposits = try await extractDeposits( + accountDeposits: summary.deposits, + newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, + unstakeData: claimsNonFungibleData, + entities: resourcesInfo, + networkID: networkID + ) + + return Common.Sections( + withdrawals: withdrawals, + deposits: deposits, + unstakingFromValidators: unstakingFromValidators + ) + + case let .validatorClaim(validatorAddresses, _): + let resourcesInfo = try await resourcesInfo(allAddresses.elements) + let withdrawals = try? await extractWithdrawals( + accountWithdraws: summary.withdrawals.aggregated, + newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, + entities: resourcesInfo, + networkID: networkID + ) + + let claimingFromValidators = try await extractValidators( + for: validatorAddresses + ) + + let deposits = try? await extractDeposits( + accountDeposits: summary.deposits.aggregated, + newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, + entities: resourcesInfo, + networkID: networkID + ) + + return Common.Sections( + withdrawals: withdrawals, + deposits: deposits, + claimingFromValidators: claimingFromValidators + ) + + case let .accountDepositSettingsUpdate( + resourcePreferencesUpdates, + depositModeUpdates, + authorizedDepositorsAdded, + authorizedDepositorsRemoved + ): + + let allAccountAddress = Set(authorizedDepositorsAdded.keys) + .union(authorizedDepositorsRemoved.keys) + .union(depositModeUpdates.keys) + .union(resourcePreferencesUpdates.keys) + + let userAccounts = try await accountsClient.getAccountsOnCurrentNetwork() // TODO: Use general one + + let validAccounts = allAccountAddress.compactMap { address in + userAccounts.first { $0.address == address } + } + + let accountDepositSetting = extractAccountDepositSetting( + for: validAccounts, + defaultDepositRuleChanges: depositModeUpdates + ) + let accountDepositExceptions = try await extractAccountDepositExceptions( + for: validAccounts, + resourcePreferenceChanges: resourcePreferencesUpdates, + authorizedDepositorsAdded: authorizedDepositorsAdded, + authorizedDepositorsRemoved: authorizedDepositorsRemoved + ) + + return Common.Sections( + accountDepositSetting: accountDepositSetting, + accountDepositExceptions: accountDepositExceptions + ) + } + } + + private func extractUserAccounts(_ allAddress: [AccountAddress]) async throws -> [Common.ReviewAccount] { + let userAccounts = try await accountsClient.getAccountsOnCurrentNetwork() + + return allAddress + .map { (address: AccountAddress) in + let userAccount = userAccounts.first { userAccount in + userAccount.address.address == address.address + } + if let userAccount { + return .user(userAccount) + } else { + return .external(address, approved: false) + } + } + } + + private func extractDapps( + addresses: [Address], + unknownTitle: (Int) -> String + ) async throws -> InteractionReviewDapps.State? { + let dApps = await extractDappEntities(addresses) + return try await extractDapps(dApps, unknownTitle: unknownTitle) + } + + private func extractDapps( + _ dAppEntities: [(address: Address, entity: InteractionReview.DappEntity?)], + unknownTitle: (Int) -> String + ) async throws -> InteractionReviewDapps.State? { + let knownDapps = dAppEntities.compactMap(\.entity).asIdentified() + let unknownDapps = try dAppEntities.filter { $0.entity == nil } + .map { try $0.address.asSpecific(type: A.self) }.asIdentified() + + guard knownDapps.count + unknownDapps.count > 0 else { return nil } + + return .init(knownDapps: knownDapps, unknownDapps: unknownDapps, unknownTitle: unknownTitle) + } + + private func extractDappEntities(_ addresses: [Address]) async -> [(address: Address, entity: InteractionReview.DappEntity?)] { + await addresses.asyncMap { + await (address: $0, entity: try? extractDappEntity($0.asGeneral)) + } + } + + private func extractDappEntity(_ entity: Address) async throws -> InteractionReview.DappEntity { + let dAppDefinitionAddress = try await onLedgerEntitiesClient.getDappDefinitionAddress(entity) + let metadata = try await onLedgerEntitiesClient.getDappMetadata(dAppDefinitionAddress, validatingDappEntity: entity) + return .init(id: dAppDefinitionAddress, metadata: metadata) + } + + private func exctractProofs(_ accountProofs: [ResourceSpecifier]) async throws -> Common.Proofs.State? { + let proofs = try await accountProofs + .uniqued() + .asyncMap(extractResourceBalanceInfo) + .flatMap { $0 } + .asyncMap(extractProofInfo) + + guard !proofs.isEmpty else { return nil } + + return Common.Proofs.State(kind: .transaction, proofs: proofs.asIdentified()) + } + + private func extractResourceBalanceInfo(specifier: ResourceSpecifier) async throws -> [(ResourceAddress, ResourceBalance.Details)] { + switch specifier { + case let .fungible(resourceAddress, amount): + return [( + resourceAddress, + .fungible( + .init( + isXRD: resourceAddress.isXRD, + amount: .init(nominalAmount: amount) + ) + ) + )] + case let .nonFungible(resourceAddress, ids): + let globalIds = ids.map { NonFungibleGlobalId(resourceAddress: resourceAddress, nonFungibleLocalId: $0) } + let tokens = try await onLedgerEntitiesClient.getNonFungibleTokenData( + .init(resource: resourceAddress, nonFungibleIds: globalIds) + ) + return tokens.map { (resourceAddress, .nonFungible($0)) } + } + } + + private func extractProofInfo(resourceAddress: ResourceAddress, details: ResourceBalance.Details) async throws -> Common.ProofEntity { + try await Common.ProofEntity( + resourceBalance: ResourceBalance( + resource: onLedgerEntitiesClient.getResource(resourceAddress, metadataKeys: .dappMetadataKeys), + details: details + ) + ) + } + + private func extractWithdrawals( + accountWithdraws: [AccountAddress: [ResourceIndicator]], + newlyCreatedNonFungibles: [NonFungibleGlobalId] = [], + poolRedemptions: [TrackedPoolRedemption] = [], + entities: ResourcesInfo = [:], + resourceAssociatedDapps: ResourceAssociatedDapps? = nil, + networkID: NetworkID + ) async throws -> Common.Accounts.State? { + var withdrawals: [Common.ReviewAccount: IdentifiedArrayOf] = [:] + let userAccounts: [Common.ReviewAccount] = try await extractUserAccounts(Array(accountWithdraws.keys)) + + for (accountAddress, resources) in accountWithdraws { + let account = try userAccounts.account(for: accountAddress) + let transfers = try await resources.asyncFlatMap { + try await transferInfo( + resourceQuantifier: $0, + newlyCreatedNonFungibles: newlyCreatedNonFungibles, + poolInteractions: poolRedemptions, + entities: entities, + resourceAssociatedDapps: resourceAssociatedDapps, + networkID: networkID, + type: .exact + ) + } + .map(\.asIdentified) + + withdrawals[account, default: []].append(contentsOf: transfers) + } + + guard !withdrawals.isEmpty else { return nil } + + let withdrawalAccounts = withdrawals.map { + Common.Account.State(account: $0.key, transfers: $0.value, isDeposit: false) + } + .asIdentified() + + return .init(accounts: withdrawalAccounts, enableCustomizeGuarantees: false) + } + + private func extractDeposits( + accountDeposits: [AccountAddress: [ResourceIndicator]], + newlyCreatedNonFungibles: [NonFungibleGlobalId] = [], + poolContributions: [TrackedPoolContribution] = [], + validatorStakes: [TrackedValidatorStake] = [], + unstakeData: [NonFungibleGlobalId: UnstakeData] = [:], + entities: ResourcesInfo = [:], + resourceAssociatedDapps: ResourceAssociatedDapps? = nil, + networkID: NetworkID + ) async throws -> Common.Accounts.State? { + let userAccounts: [Common.ReviewAccount] = try await extractUserAccounts(Array(accountDeposits.keys)) + let defaultDepositGuarantee = await appPreferencesClient.getPreferences().transaction.defaultDepositGuarantee + + var deposits: [Common.ReviewAccount: IdentifiedArrayOf] = [:] + + for (accountAddress, accountDeposits) in accountDeposits { + let account = try userAccounts.account(for: accountAddress) + let transfers = try await accountDeposits.asyncFlatMap { + let aux = try await transferInfo( + resourceQuantifier: $0, + newlyCreatedNonFungibles: newlyCreatedNonFungibles, + poolInteractions: poolContributions, + validatorStakes: validatorStakes, + unstakeData: unstakeData, + entities: entities, + resourceAssociatedDapps: resourceAssociatedDapps, + networkID: networkID, + type: $0.transferType, + defaultDepositGuarantee: defaultDepositGuarantee + ) + return aux + } + .map(\.asIdentified) + + deposits[account, default: []].append(contentsOf: transfers) + } + + let depositAccounts = deposits + .filter { !$0.value.isEmpty } + .map { Common.Account.State(account: $0.key, transfers: $0.value, isDeposit: true) } + .asIdentified() + + guard !depositAccounts.isEmpty else { return nil } + + let requiresGuarantees = !depositAccounts.customizableGuarantees.isEmpty + return .init(accounts: depositAccounts, enableCustomizeGuarantees: requiresGuarantees) + } + + func extractValidators(for addresses: [ValidatorAddress]) async throws -> Common.ValidatorsState? { + guard !addresses.isEmpty else { return nil } + + let validators = try await onLedgerEntitiesClient.getEntities( + addresses: addresses.map(\.asGeneral), + metadataKeys: .resourceMetadataKeys + ) + + .compactMap { entity -> Common.ValidatorState? in + guard let validator = entity.validator else { return nil } + return .init( + address: validator.address, + name: validator.metadata.name, + thumbnail: validator.metadata.iconURL + ) + } + + guard validators.count == addresses.count else { + struct FailedToExtractValidatorInformation: Error {} + throw FailedToExtractValidatorInformation() + } + + return .init(validators: validators) + } + + func extractAccountDepositSetting( + for validAccounts: [Account], + defaultDepositRuleChanges: [AccountAddress: AccountDefaultDepositRule] + ) -> TransactionReview.DepositSettingState? { + let depositSettingChanges: [TransactionReview.DepositSettingChange] = validAccounts.compactMap { account in + guard let depositRuleChange = defaultDepositRuleChanges[account.address] else { return nil } + return .init(account: account, ruleChange: depositRuleChange) + } + + guard !depositSettingChanges.isEmpty else { return nil } + + return .init(changes: IdentifiedArray(uncheckedUniqueElements: depositSettingChanges)) + } + + func extractAccountDepositExceptions( + for validAccounts: [Account], + resourcePreferenceChanges: [AccountAddress: [ResourceAddress: ResourcePreferenceUpdate]], + authorizedDepositorsAdded: [AccountAddress: [ResourceOrNonFungible]], + authorizedDepositorsRemoved: [AccountAddress: [ResourceOrNonFungible]] + ) async throws -> TransactionReview.DepositExceptionsState? { + let exceptionChanges: [TransactionReview.DepositExceptionsChange] = try await validAccounts.asyncCompactMap { account in + let resourcePreferenceChanges = try await resourcePreferenceChanges[account.address]? + .asyncMap { resourcePreference in + try await TransactionReview.DepositExceptionsChange.ResourcePreferenceChange( + resource: onLedgerEntitiesClient.getResource(resourcePreference.key), + change: resourcePreference.value + ) + } ?? [] + + let authorizedDepositorChanges = try await { + var changes: [TransactionReview.DepositExceptionsChange.AllowedDepositorChange] = [] + if let authorizedDepositorsAdded = authorizedDepositorsAdded[account.address] { + let added = try await authorizedDepositorsAdded.asyncMap { resourceOrNonFungible in + let resourceAddress = resourceOrNonFungible.resourceAddress + return try await TransactionReview.DepositExceptionsChange.AllowedDepositorChange( + resource: onLedgerEntitiesClient.getResource(resourceAddress), + change: .added + ) + } + changes.append(contentsOf: added) + } + if let authorizedDepositorsRemoved = authorizedDepositorsRemoved[account.address] { + let removed = try await authorizedDepositorsRemoved.asyncMap { resourceOrNonFungible in + let resourceAddress = resourceOrNonFungible.resourceAddress + return try await TransactionReview.DepositExceptionsChange.AllowedDepositorChange( + resource: onLedgerEntitiesClient.getResource(resourceAddress), + change: .removed + ) + } + changes.append(contentsOf: removed) + } + + return changes + }() + + guard !resourcePreferenceChanges.isEmpty || !authorizedDepositorChanges.isEmpty else { return nil } + + return TransactionReview.DepositExceptionsChange( + account: account, + resourcePreferenceChanges: IdentifiedArray(uncheckedUniqueElements: resourcePreferenceChanges), + allowedDepositorChanges: IdentifiedArray(uncheckedUniqueElements: authorizedDepositorChanges) + ) + } + + guard !exceptionChanges.isEmpty else { return nil } + + return .init(changes: IdentifiedArray(uncheckedUniqueElements: exceptionChanges)) + } + + private func perPoolUnitDapps( + _ dappEntities: [(address: Address, entity: InteractionReview.DappEntity?)], + poolInteractions: [some TrackedPoolInteraction] + ) throws -> ResourceAssociatedDapps { + try Dictionary(keysWithValues: dappEntities.compactMap { data -> (ResourceAddress, OnLedgerEntity.Metadata)? in + let poolUnitResource: ResourceAddress? = poolInteractions + .first(where: { $0.poolAddress.asGeneral == data.address })? + .poolUnitsResourceAddress + + guard let poolUnitResource, + let dAppMetadata = data.entity?.metadata + else { + return nil + } + + return (poolUnitResource, dAppMetadata) + }) + } +} + +extension InteractionReview.MiddleSections { + struct ResourceEntityNotFound: Error { + let address: String + } + + struct FailedToGetDataForAllNFTs: Error {} + struct FailedToGetPoolUnitDetails: Error {} + struct StakeUnitAddressMismatch: Error {} + struct MissingTrackedValidatorStake: Error {} + struct MissingPositiveTotalSupply: Error {} + struct InvalidStakeClaimToken: Error {} + struct MissingStakeClaimTokenData: Error {} + + func transferInfo( + resourceQuantifier: ResourceIndicator, + newlyCreatedNonFungibles: [NonFungibleGlobalId] = [], + poolInteractions: [some TrackedPoolInteraction] = [], + validatorStakes: [TrackedValidatorStake] = [], + unstakeData: [NonFungibleGlobalId: UnstakeData] = [:], + entities: ResourcesInfo = [:], + resourceAssociatedDapps: ResourceAssociatedDapps? = nil, + networkID: NetworkID, + type: TransactionReview.TransferType, + defaultDepositGuarantee: Decimal192 = 1 + ) async throws -> [ResourceBalance] { + let resourceAddress: ResourceAddress = resourceQuantifier.resourceAddress + + guard let resourceInfo = entities[resourceAddress] else { + throw ResourceEntityNotFound(address: resourceAddress.address) + } + + switch resourceQuantifier { + case let .fungible(_, source): + switch resourceInfo { + case let .left(resource): + return try await [onLedgerEntitiesClient.fungibleResourceBalance( + resource, + resourceQuantifier: source, + poolContributions: poolInteractions, + validatorStakes: validatorStakes, + entities: entities, + resourceAssociatedDapps: resourceAssociatedDapps, + networkID: networkID, + defaultDepositGuarantee: defaultDepositGuarantee + )] + case let .right(newEntityMetadata): + // A newly created fungible resource + + let resource: OnLedgerEntity.Resource = .init( + resourceAddress: resourceAddress, + metadata: newEntityMetadata + ) + + let details: ResourceBalance.Fungible = .init( + isXRD: false, + amount: .init(nominalAmount: source.amount), + guarantee: nil + ) + + return [.init(resource: resource, details: .fungible(details), isHidden: false)] + } + + case let .nonFungible(_, indicator): + return try await onLedgerEntitiesClient.nonFungibleResourceBalances( + resourceInfo, + resourceAddress: resourceAddress, + resourceQuantifier: indicator, + unstakeData: unstakeData, + newlyCreatedNonFungibles: newlyCreatedNonFungibles + ) + } + } +} diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+Sections.swift b/RadixWallet/Features/InteractionReview/Sections/MiddleSections+Simulate.swift similarity index 96% rename from RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+Sections.swift rename to RadixWallet/Features/InteractionReview/Sections/MiddleSections+Simulate.swift index ee8b3ec04a..08b3242b27 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+Sections.swift +++ b/RadixWallet/Features/InteractionReview/Sections/MiddleSections+Simulate.swift @@ -1,4 +1,4 @@ -extension PreAuthorizationReview { +extension InteractionReview.MiddleSections { func simulateSections() async throws -> Common.Sections? { let xrdBalance: ResourceBalance = .init(resource: .init(resourceAddress: .sampleStokenetXRD, metadata: .init(name: "Radix", symbol: "XRD", isComplete: true)), details: .fungible(.init(isXRD: true, amount: .init(nominalAmount: .five)))) let idResourceBalance = xrdBalance.asIdentified diff --git a/RadixWallet/Features/InteractionReview/Sections/MiddleSections+View.swift b/RadixWallet/Features/InteractionReview/Sections/MiddleSections+View.swift new file mode 100644 index 0000000000..672193de46 --- /dev/null +++ b/RadixWallet/Features/InteractionReview/Sections/MiddleSections+View.swift @@ -0,0 +1,201 @@ +import SwiftUI + +// MARK: - InteractionReview.MiddleSections.View +extension InteractionReview.MiddleSections { + struct View: SwiftUI.View { + let store: StoreOf + + var body: some SwiftUI.View { + WithPerceptionTracking { + VStack(alignment: .leading, spacing: .medium1) { + withdrawals + + VStack(alignment: .leading, spacing: .medium1) { + contributingToPools + + redeemingFromPools + +// if let viewState = viewStore.stakingToValidators { +// stakingToValidatorsSection(viewState) +// } +// +// if let viewState = viewStore.unstakingFromValidators { +// unstakingFromValidatorsSection(viewState) +// } +// +// if let viewState = viewStore.claimingFromValidators { +// claimingFromValidatorsSection(viewState) +// } + + dAppsUsed + + deposits + } + .frame(maxWidth: .infinity, alignment: .leading) // necessary? + .background(alignment: .trailing) { + if store.showTransferLine { + Common.TransferLineView() + } + } + +// if let viewState = viewStore.depositSettingSection { +// accountDepositSettingSection(viewState) +// } +// +// if let viewState = viewStore.depositExceptionsSection { +// accountDepositExceptionsSection(viewState) +// } + } + .animation(.easeInOut, value: store.contributingToPools?.isExpanded) + .animation(.easeInOut, value: store.redeemingFromPools?.isExpanded) + .animation(.easeInOut, value: store.dAppsUsed?.isExpanded) + } + .destinations(with: store) + } + + @ViewBuilder + private var withdrawals: some SwiftUI.View { + if let childStore = store.scope(state: \.withdrawals, action: \.child.withdrawals) { + VStack(alignment: .leading, spacing: .small2) { + Common.HeadingView.withdrawing + Common.Accounts.View(store: childStore) + } + } + } + + @ViewBuilder + private var contributingToPools: some SwiftUI.View { + if let childStore = store.scope(state: \.contributingToPools, action: \.child.contributingToPools) { + VStack(alignment: .leading, spacing: .small2) { + let isExpanded = childStore.isExpanded + Common.ExpandableHeadingView(heading: .contributingToPools, isExpanded: isExpanded) { +// store.send(.view(.expandContributingToPoolsTapped)) + } + if isExpanded { + InteractionReviewPools.View(store: childStore) + .transition(.opacity.combined(with: .scale(scale: 0.95))) + } + } + } + } + + @ViewBuilder + private var redeemingFromPools: some SwiftUI.View { + if let childStore = store.scope(state: \.redeemingFromPools, action: \.child.redeemingFromPools) { + VStack(alignment: .leading, spacing: .small2) { + let isExpanded = childStore.isExpanded + Common.ExpandableHeadingView(heading: .redeemingFromPools, isExpanded: isExpanded) { +// store.send(.view(.expandRedeemingFromPoolsTapped)) + } + if isExpanded { + InteractionReviewPools.View(store: childStore) + .transition(.opacity.combined(with: .scale(scale: 0.95))) + } + } + } + } + + @ViewBuilder + private var dAppsUsed: some SwiftUI.View { + if let childStore = store.scope(state: \.dAppsUsed, action: \.child.dAppsUsed) { + VStack(alignment: .leading, spacing: .small2) { + let isExpanded = childStore.isExpanded + Common.ExpandableHeadingView(heading: .usingDapps, isExpanded: isExpanded) { +// store.send(.view(.expandDappsUsedTapped)) + } + if isExpanded { + InteractionReviewDappsUsed.View(store: childStore) + .transition(.opacity.combined(with: .scale(scale: 0.95))) + } + } + } + } + + @ViewBuilder + private var deposits: some SwiftUI.View { + if let childStore = store.scope(state: \.deposits, action: \.child.deposits) { + VStack(alignment: .leading, spacing: .small2) { + Common.HeadingView.depositing + Common.Accounts.View(store: childStore) + } + } + } + } +} + +extension InteractionReview.MiddleSections.State { + var showTransferLine: Bool { + withdrawals != nil && deposits != nil + } +} + +extension StoreOf { + var destination: PresentationStoreOf { + func scopeState(state: State) -> PresentationState { + state.$destination + } + return scope(state: scopeState, action: Action.destination) + } +} + +@MainActor +private extension View { + typealias Destination = InteractionReview.MiddleSections.Destination + + func destinations(with store: StoreOf) -> some View { + let destinationStore = store.destination + return dApp(with: destinationStore) + .fungibleTokenDetails(with: destinationStore) + .nonFungibleTokenDetails(with: destinationStore) + .lsuDetails(with: destinationStore) + .poolUnitDetails(with: destinationStore) + .unknownComponents(with: destinationStore) + .rawTransactionAlert(with: destinationStore) + } + + private func rawTransactionAlert(with destinationStore: PresentationStoreOf) -> some View { + alert(store: destinationStore.scope(state: \.rawTransactionAlert, action: \.rawTransactionAlert)) + } + + private func dApp(with destinationStore: PresentationStoreOf) -> some View { + sheet(store: destinationStore.scope(state: \.dApp, action: \.dApp)) { detailsStore in + WithNavigationBar { + destinationStore.send(.dismiss) + } content: { + DappDetails.View(store: detailsStore) + } + } + } + + private func unknownComponents(with destinationStore: PresentationStoreOf) -> some View { + sheet(store: destinationStore.scope(state: \.unknownDappComponents, action: \.unknownDappComponents)) { + InteractionReview.UnknownDappComponents.View(store: $0) + .inNavigationStack + .presentationDetents([.medium]) + } + } + + private func fungibleTokenDetails(with destinationStore: PresentationStoreOf) -> some View { + sheet(store: destinationStore.scope(state: \.fungibleTokenDetails, action: \.fungibleTokenDetails)) { + FungibleTokenDetails.View(store: $0) + } + } + + private func nonFungibleTokenDetails(with destinationStore: PresentationStoreOf) -> some View { + sheet(store: destinationStore.scope(state: \.nonFungibleTokenDetails, action: \.nonFungibleTokenDetails)) { + NonFungibleTokenDetails.View(store: $0) + } + } + + private func lsuDetails(with destinationStore: PresentationStoreOf) -> some View { + sheet(store: destinationStore.scope(state: \.lsuDetails, action: \.lsuDetails)) { + LSUDetails.View(store: $0) + } + } + + private func poolUnitDetails(with destinationStore: PresentationStoreOf) -> some View { + sheet(store: destinationStore.scope(state: \.poolUnitDetails, action: \.poolUnitDetails)) { + PoolUnitDetails.View(store: $0) + } + } +} diff --git a/RadixWallet/Features/InteractionReview/Sections/MiddleSections.swift b/RadixWallet/Features/InteractionReview/Sections/MiddleSections.swift new file mode 100644 index 0000000000..43c93af3ff --- /dev/null +++ b/RadixWallet/Features/InteractionReview/Sections/MiddleSections.swift @@ -0,0 +1,283 @@ +// MARK: - InteractionReview.MiddleSections +extension InteractionReview { + @Reducer + struct MiddleSections: Sendable, FeatureReducer { + typealias Common = InteractionReview + + @ObservableState + struct State: Sendable, Hashable { + var withdrawals: Accounts.State? = nil + var dAppsUsed: InteractionReviewDappsUsed.State? = nil + var deposits: Accounts.State? = nil + + var contributingToPools: InteractionReviewPools.State? = nil + var redeemingFromPools: InteractionReviewPools.State? = nil + + var stakingToValidators: InteractionReview.ValidatorsState? = nil + var unstakingFromValidators: InteractionReview.ValidatorsState? = nil + var claimingFromValidators: InteractionReview.ValidatorsState? = nil + + var accountDepositSetting: TransactionReview.DepositSettingState? = nil + var accountDepositExceptions: TransactionReview.DepositExceptionsState? = nil + + // The proofs are set here (within the resolve logic) but should be rendered and handled by the parent view, since they may be placed outside the Sections. + var proofs: Proofs.State? = nil + + @Presents + var destination: Destination.State? = nil + } + + typealias Action = FeatureAction + + enum ViewAction: Sendable, Equatable { + case appeared + } + + enum InternalAction: Sendable, Equatable { + case resolveExecutionSummary(ExecutionSummary, NetworkID) + case simulate + case setSections(Common.Sections?) + } + + @CasePathable + enum ChildAction: Sendable, Equatable { + case withdrawals(Common.Accounts.Action) + case deposits(Common.Accounts.Action) + case dAppsUsed(InteractionReviewDappsUsed.Action) + case contributingToPools(InteractionReviewPools.Action) + case redeemingFromPools(InteractionReviewPools.Action) + } + + enum DelegateAction: Sendable, Hashable { + case failedToResolveSections + case showCustomizeGuarantees([TransactionReviewGuarantee.State]) + } + + struct Destination: DestinationReducer { + @CasePathable + enum State: Sendable, Hashable { + case dApp(DappDetails.State) + case fungibleTokenDetails(FungibleTokenDetails.State) + case nonFungibleTokenDetails(NonFungibleTokenDetails.State) + case poolUnitDetails(PoolUnitDetails.State) + case lsuDetails(LSUDetails.State) + case unknownDappComponents(Common.UnknownDappComponents.State) + case rawTransactionAlert(AlertState) + } + + @CasePathable + enum Action: Sendable, Equatable { + case dApp(DappDetails.Action) + case fungibleTokenDetails(FungibleTokenDetails.Action) + case nonFungibleTokenDetails(NonFungibleTokenDetails.Action) + case lsuDetails(LSUDetails.Action) + case poolUnitDetails(PoolUnitDetails.Action) + case unknownDappComponents(Common.UnknownDappComponents.Action) + case rawTransactionAlert(RawTransactionAlert) + + enum RawTransactionAlert: Sendable, Equatable { + case continueTapped + } + } + + var body: some ReducerOf { + Scope(state: \.dApp, action: \.dApp) { + DappDetails() + } + Scope(state: \.fungibleTokenDetails, action: \.fungibleTokenDetails) { + FungibleTokenDetails() + } + Scope(state: \.nonFungibleTokenDetails, action: \.nonFungibleTokenDetails) { + NonFungibleTokenDetails() + } + Scope(state: \.poolUnitDetails, action: \.poolUnitDetails) { + PoolUnitDetails() + } + Scope(state: \.lsuDetails, action: \.lsuDetails) { + LSUDetails() + } + Scope(state: \.unknownDappComponents, action: \.unknownDappComponents) { + Common.UnknownDappComponents() + } + } + } + + @Dependency(\.onLedgerEntitiesClient) var onLedgerEntitiesClient + @Dependency(\.accountsClient) var accountsClient + @Dependency(\.appPreferencesClient) var appPreferencesClient + + var body: some ReducerOf { + Reduce(core) + .ifLet(\.withdrawals, action: \.child.withdrawals) { + Common.Accounts() + } + .ifLet(\.deposits, action: \.child.deposits) { + Common.Accounts() + } + .ifLet(\.dAppsUsed, action: \.child.dAppsUsed) { + InteractionReviewDappsUsed() + } + .ifLet(\.contributingToPools, action: \.child.contributingToPools) { + InteractionReviewPools() + } + .ifLet(\.redeemingFromPools, action: \.child.redeemingFromPools) { + InteractionReviewPools() + } + .ifLet(destinationPath, action: /Action.destination) { + Destination() + } + } + + private let destinationPath: WritableKeyPath> = \.$destination + + func reduce(into state: inout State, viewAction: ViewAction) -> Effect { + switch viewAction { + case .appeared: + .none + } + } + + func reduce(into state: inout State, internalAction: InternalAction) -> Effect { + switch internalAction { + case let .resolveExecutionSummary(executionSummary, networkID): + return .run { send in + let sections = try await sections(for: executionSummary, networkID: networkID) + await send(.internal(.setSections(sections))) + } catch: { error, send in + loggerGlobal.error("Failed to extract sections from ExecutionSummary, error: \(error)") + await send(.internal(.setSections(nil))) + } + + case .simulate: + return .run { send in + let sections = try await simulateSections() + await send(.internal(.setSections(sections))) + } catch: { error, send in + loggerGlobal.error("Failed to extract sections, error: \(error)") + await send(.internal(.setSections(nil))) + } + + case let .setSections(sections): + guard let sections else { + state.destination = .rawTransactionAlert(.rawTransaction) + return .send(.delegate(.failedToResolveSections)) + } + state.withdrawals = sections.withdrawals + state.dAppsUsed = sections.dAppsUsed + state.contributingToPools = sections.contributingToPools + state.redeemingFromPools = sections.redeemingFromPools + state.stakingToValidators = sections.stakingToValidators + state.unstakingFromValidators = sections.unstakingFromValidators + state.claimingFromValidators = sections.claimingFromValidators + state.deposits = sections.deposits + state.accountDepositSetting = sections.accountDepositSetting + state.accountDepositExceptions = sections.accountDepositExceptions + state.proofs = sections.proofs + return .none + } + } + + func reduce(into state: inout State, childAction: ChildAction) -> Effect { + switch childAction { + case let .withdrawals(.delegate(.showAsset(transfer, token))), + let .deposits(.delegate(.showAsset(transfer, token))): + return resourceDetailsEffect(state: &state, resource: transfer.resource, details: transfer.details, nft: token) + + case let .dAppsUsed(.delegate(.openDapp(dAppID))), let .contributingToPools(.delegate(.openDapp(dAppID))), let .redeemingFromPools(.delegate(.openDapp(dAppID))): + state.destination = .dApp(.init(dAppDefinitionAddress: dAppID)) + return .none + + case let .dAppsUsed(.delegate(.openUnknownAddresses(components))): + state.destination = .unknownDappComponents(.init( + title: L10n.TransactionReview.unknownComponents(components.count), + rowHeading: L10n.Common.component, + addresses: components.map { .component($0) } + )) + return .none + + case let .contributingToPools(.delegate(.openUnknownAddresses(pools))), let .redeemingFromPools(.delegate(.openUnknownAddresses(pools))): + state.destination = .unknownDappComponents(.init( + title: L10n.TransactionReview.unknownPools(pools.count), + rowHeading: L10n.Common.pool, + addresses: pools.map { .resourcePool($0) } + )) + return .none + + case .deposits(.delegate(.showCustomizeGuarantees)): + guard let guarantees = state.deposits?.accounts.customizableGuarantees, !guarantees.isEmpty else { return .none } + return .send(.delegate(.showCustomizeGuarantees(guarantees))) + + default: + return .none + } + } + } +} + +private extension InteractionReview.MiddleSections { + func resourceDetailsEffect( + state: inout State, + resource: OnLedgerEntity.Resource, + details: ResourceBalance.Details, + nft: OnLedgerEntity.NonFungibleToken? = nil + ) -> Effect { + switch details { + case let .fungible(details): + state.destination = .fungibleTokenDetails(.init( + resourceAddress: resource.resourceAddress, + resource: .success(resource), + ownedFungibleResource: .init( + resourceAddress: resource.resourceAddress, + atLedgerState: resource.atLedgerState, + amount: details.amount, + metadata: resource.metadata + ), + isXRD: details.isXRD + )) + + case let .nonFungible(details): + state.destination = .nonFungibleTokenDetails(.init( + resourceAddress: resource.resourceAddress, + resourceDetails: .success(resource), + token: details, + ledgerState: resource.atLedgerState + )) + + case let .liquidStakeUnit(details): + state.destination = .lsuDetails(.init( + validator: details.validator, + stakeUnitResource: .init(resource: details.resource, amount: .init(nominalAmount: details.amount)), + xrdRedemptionValue: details.worth + )) + + case let .poolUnit(details): + state.destination = .poolUnitDetails(.init(resourcesDetails: details.details)) + + case let .stakeClaimNFT(details): + state.destination = .nonFungibleTokenDetails(.init( + resourceAddress: resource.resourceAddress, + resourceDetails: .success(resource), + token: nft, + ledgerState: resource.atLedgerState, + stakeClaim: details.stakeClaimTokens.stakeClaims.first, + isClaimStakeEnabled: false + )) + } + + return .none + } +} + +extension AlertState { + static var rawTransaction: AlertState { + AlertState { + TextState(L10n.TransactionReview.NonConformingManifestWarning.title) + } actions: { + ButtonState(action: .continueTapped) { + TextState(L10n.Common.continue) + } + } message: { + TextState(L10n.TransactionReview.NonConformingManifestWarning.message) + } + } +} diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index 1ae6a5b5a1..e4e3a46d67 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -103,17 +103,7 @@ extension PreAuthorizationReview { private var details: some SwiftUI.View { VStack(alignment: .leading, spacing: .medium1) { - withdrawals - - VStack(alignment: .leading, spacing: .medium1) { - deposits - } - .frame(maxWidth: .infinity, alignment: .leading) // necessary? - .background(alignment: .trailing) { - if store.showTransferLine { - Common.TransferLineView() - } - } + sections proofs } @@ -129,24 +119,9 @@ extension PreAuthorizationReview { } } - @ViewBuilder - private var withdrawals: some SwiftUI.View { - if let childStore = store.scope(state: \.withdrawals, action: \.child.withdrawals) { - VStack(alignment: .leading, spacing: .small2) { - Common.HeadingView.withdrawing - Common.Accounts.View(store: childStore) - } - } - } - - @ViewBuilder - private var deposits: some SwiftUI.View { - if let childStore = store.scope(state: \.deposits, action: \.child.deposits) { - VStack(alignment: .leading, spacing: .small2) { - Common.HeadingView.depositing - Common.Accounts.View(store: childStore) - } - } + private var sections: some SwiftUI.View { + let childStore = store.scope(state: \.sections, action: \.child.sections) + return Common.MiddleSections.View(store: childStore) } @ViewBuilder diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 629629981d..1e5cd87785 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -14,8 +14,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { var secondsToExpiration: Int? // Sections - var withdrawals: Common.Accounts.State? = nil - var deposits: Common.Accounts.State? = nil + var sections: Common.MiddleSections.State = .init() var proofs: Common.Proofs.State? = nil init() {} @@ -31,13 +30,11 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { @CasePathable enum ChildAction: Sendable, Equatable { - case withdrawals(Common.Accounts.Action) - case deposits(Common.Accounts.Action) + case sections(Common.MiddleSections.Action) case proofs(Common.Proofs.Action) } enum InternalAction: Sendable, Equatable { - case setSections(Common.Sections?) case updateSecondsToExpiration(Date) } @@ -45,13 +42,10 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { @Dependency(\.pasteboardClient) var pasteboardClient var body: some ReducerOf { + Scope(state: \.sections, action: \.child.sections) { + Common.MiddleSections() + } Reduce(core) - .ifLet(\.withdrawals, action: \.child.withdrawals) { - Common.Accounts() - } - .ifLet(\.deposits, action: \.child.deposits) { - Common.Accounts() - } .ifLet(\.proofs, action: \.child.proofs) { Common.Proofs() } @@ -88,33 +82,26 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { func reduce(into state: inout State, internalAction: InternalAction) -> Effect { switch internalAction { - case let .setSections(sections): - guard let sections else { - // TOOD: Show alert to indicate manifest is complex - state.displayMode = .raw(state.exampleRaw) - return .none - } - state.withdrawals = sections.withdrawals - state.deposits = sections.deposits - state.proofs = sections.proofs - return .none - case let .updateSecondsToExpiration(expiration): state.secondsToExpiration = Int(expiration.timeIntervalSinceNow) return .none } } + + func reduce(into state: inout State, childAction: ChildAction) -> Effect { + switch childAction { + case let .sections(.internal(.setSections(sections))): + state.proofs = sections?.proofs + return .none + default: + return .none + } + } } private extension PreAuthorizationReview { func getSections() -> Effect { - .run { send in - let sections = try await simulateSections() - await send(.internal(.setSections(sections))) - } catch: { error, send in - loggerGlobal.error("Failed to extract PreAuthorization sections, error: \(error)") - await send(.internal(.setSections(nil))) - } + .send(.child(.sections(.internal(.simulate)))) } func startTimer(expirationDate: Date) -> Effect { diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index a9351587a4..7b69237b9f 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -155,42 +155,7 @@ extension TransactionReview { VStack(spacing: .medium1) { messageSection(with: viewStore.message) - withdrawalsSection - - VStack(spacing: .medium1) { - contributingToPools(isExpanded: viewStore.isExpandedContributingToPools) - - redeemingFromPools(isExpanded: viewStore.isExpandedRedeemingFromPools) - - if let viewState = viewStore.stakingToValidators { - stakingToValidatorsSection(viewState) - } - - if let viewState = viewStore.unstakingFromValidators { - unstakingFromValidatorsSection(viewState) - } - - if let viewState = viewStore.claimingFromValidators { - claimingFromValidatorsSection(viewState) - } - - usingDappsSection(isExpanded: viewStore.isExpandedDappUsed) - - depositsSection - } - .background(alignment: .trailing) { - if viewStore.showTransferLine { - Common.TransferLineView() - } - } - - if let viewState = viewStore.depositSettingSection { - accountDepositSettingSection(viewState) - } - - if let viewState = viewStore.depositExceptionsSection { - accountDepositExceptionsSection(viewState) - } + sections } .padding(.top, .small1) .padding(.horizontal, .medium3) @@ -261,6 +226,11 @@ extension TransactionReview { } } + private var sections: some SwiftUI.View { + let childStore = store.scope(state: \.sections, action: \.child.sections) + return Common.MiddleSections.View(store: childStore) + } + private var withdrawalsSection: some SwiftUI.View { IfLetStore(store.scope(state: \.withdrawals) { .child(.withdrawals($0)) }) { childStore in VStack(alignment: .leading, spacing: .small2) { diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift index 9f7664204a..44d1a70d47 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift @@ -21,6 +21,7 @@ struct TransactionReview: Sendable, FeatureReducer { var reviewedTransaction: ReviewedTransaction? = nil + var sections: Common.MiddleSections.State = .init() var withdrawals: Common.Accounts.State? = nil var dAppsUsed: InteractionReviewDappsUsed.State? = nil var contributingToPools: InteractionReviewPools.State? = nil @@ -109,7 +110,9 @@ struct TransactionReview: Sendable, FeatureReducer { case approvalSliderSlid } + @CasePathable enum ChildAction: Sendable, Equatable { + case sections(Common.MiddleSections.Action) case withdrawals(Common.Accounts.Action) case deposits(Common.Accounts.Action) case dAppsUsed(InteractionReviewDappsUsed.Action) @@ -213,6 +216,9 @@ struct TransactionReview: Sendable, FeatureReducer { init() {} var body: some ReducerOf { + Scope(state: \.sections, action: \.child.sections) { + Common.MiddleSections() + } Reduce(core) .ifLet(\.networkFee, action: /Action.child .. ChildAction.networkFee) { TransactionReviewNetworkFee() @@ -344,6 +350,20 @@ struct TransactionReview: Sendable, FeatureReducer { func reduce(into state: inout State, childAction: ChildAction) -> Effect { switch childAction { + case let .sections(.internal(.setSections(sections))): + state.proofs = sections?.proofs + return .none + + case let .sections(.delegate(delegateAction)): + switch delegateAction { + case .failedToResolveSections: + return showRawTransaction(&state) + + case let .showCustomizeGuarantees(guarantees): + state.destination = .customizeGuarantees(.init(guarantees: guarantees.asIdentified())) + return .none + } + case let .withdrawals(.delegate(.showAsset(transfer, token))), let .deposits(.delegate(.showAsset(transfer, token))): return resourceDetailsEffect(state: &state, resource: transfer.resource, details: transfer.details, nft: token) @@ -368,12 +388,6 @@ struct TransactionReview: Sendable, FeatureReducer { )) return .none - case .deposits(.delegate(.showCustomizeGuarantees)): - guard let guarantees = state.deposits?.accounts.customizableGuarantees, !guarantees.isEmpty else { return .none } - state.destination = .customizeGuarantees(.init(guarantees: guarantees.asIdentified())) - - return .none - case let .proofs(.delegate(.showAsset(proof))): let resource = proof.resourceBalance.resource return resourceDetailsEffect(state: &state, resource: resource, details: proof.resourceBalance.details) @@ -622,14 +636,7 @@ extension TransactionReview { state.networkFee = .init(reviewedTransaction: reviewedTransaction) - return .run { send in - let sections = try await sections(for: executionSummary, networkID: networkID) - await send(.internal(.updateSections(sections))) - } catch: { error, send in - loggerGlobal.error("Failed to extract transaction content, error: \(error)") - // FIXME: propagate/display error? - await send(.internal(.updateSections(nil))) - } + return .send(.child(.sections(.internal(.resolveExecutionSummary(executionSummary, networkID))))) } func showRawTransaction(_ state: inout State) -> Effect { From f406c97d216b5e323dc2dc9c4224a5e3dbd88e7d Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 22 Oct 2024 12:42:53 -0300 Subject: [PATCH 21/63] more changes --- RadixWallet.xcodeproj/project.pbxproj | 44 +- .../OnLedgerEntitiesClient+ComplexTypes.swift | 12 +- .../MiddleSections+ExecutionSummary.swift | 649 ------------------ .../Sections/MiddleSections.swift | 283 -------- .../Sections/Sections+Data.swift | 21 + .../Sections/Sections+ExecutionSummary.swift} | 43 +- ...Simulate.swift => Sections+Simulate.swift} | 6 +- ...ections+View.swift => Sections+View.swift} | 18 +- .../InteractionReview/Sections/Sections.swift | 290 +++++++- .../PreAuthorizationReview+View.swift | 2 +- .../PreAuthorizationReview.swift | 6 +- .../TransactionReview+View.swift | 2 +- .../TransactionReview.swift | 8 +- 13 files changed, 364 insertions(+), 1020 deletions(-) delete mode 100644 RadixWallet/Features/InteractionReview/Sections/MiddleSections+ExecutionSummary.swift delete mode 100644 RadixWallet/Features/InteractionReview/Sections/MiddleSections.swift create mode 100644 RadixWallet/Features/InteractionReview/Sections/Sections+Data.swift rename RadixWallet/Features/{TransactionReviewFeature/TransactionReview+Sections.swift => InteractionReview/Sections/Sections+ExecutionSummary.swift} (95%) rename RadixWallet/Features/InteractionReview/Sections/{MiddleSections+Simulate.swift => Sections+Simulate.swift} (91%) rename RadixWallet/Features/InteractionReview/Sections/{MiddleSections+View.swift => Sections+View.swift} (91%) diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index 0edbf1c498..54267c7b46 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -722,16 +722,16 @@ 5B272DD92C36E93100B74F1F /* AppEventsClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B272DD82C36E93100B74F1F /* AppEventsClient+Live.swift */; }; 5B272DDB2C36E9D300B74F1F /* AppEventsClient+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B272DDA2C36E9D300B74F1F /* AppEventsClient+Test.swift */; }; 5B27FBD92CC67655002975BE /* HeadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBD82CC67655002975BE /* HeadingView.swift */; }; - 5B27FBE02CC6CCBE002975BE /* Sections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBDF2CC6CCBE002975BE /* Sections.swift */; }; + 5B27FBE02CC6CCBE002975BE /* Sections+Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBDF2CC6CCBE002975BE /* Sections+Data.swift */; }; 5B27FBEA2CC70CA1002975BE /* ValidatorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBE92CC70C9D002975BE /* ValidatorsView.swift */; }; 5B27FBEC2CC70E87002975BE /* ExpandableHeadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBEB2CC70E87002975BE /* ExpandableHeadingView.swift */; }; 5B27FBEE2CC70F2D002975BE /* InteractionReview+Typealias.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBED2CC70F2D002975BE /* InteractionReview+Typealias.swift */; }; 5B27FBF02CC70F59002975BE /* Kind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBEF2CC70F57002975BE /* Kind.swift */; }; 5B27FBF52CC713B6002975BE /* UnknownDappComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBF42CC713B5002975BE /* UnknownDappComponents.swift */; }; - 5B27FBFD2CC7E6C1002975BE /* MiddleSections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBFB2CC7E6C1002975BE /* MiddleSections.swift */; }; - 5B27FBFE2CC7E6C1002975BE /* MiddleSections+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBFC2CC7E6C1002975BE /* MiddleSections+View.swift */; }; - 5B27FC002CC7E783002975BE /* MiddleSections+ExecutionSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBFF2CC7E77B002975BE /* MiddleSections+ExecutionSummary.swift */; }; - 5B27FC022CC7ECC9002975BE /* MiddleSections+Simulate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FC012CC7ECC2002975BE /* MiddleSections+Simulate.swift */; }; + 5B27FBFD2CC7E6C1002975BE /* Sections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBFB2CC7E6C1002975BE /* Sections.swift */; }; + 5B27FBFE2CC7E6C1002975BE /* Sections+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBFC2CC7E6C1002975BE /* Sections+View.swift */; }; + 5B27FC002CC7E783002975BE /* Sections+ExecutionSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBFF2CC7E77B002975BE /* Sections+ExecutionSummary.swift */; }; + 5B27FC022CC7ECC9002975BE /* Sections+Simulate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FC012CC7ECC2002975BE /* Sections+Simulate.swift */; }; 5B2A45022BD6680400AEC8AD /* ContactSupportClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */; }; 5B2A45042BD6689100AEC8AD /* ContactSupportClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */; }; 5B3C48A92C7E190C00DB160D /* AssetRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B3C48A82C7E190C00DB160D /* AssetRow.swift */; }; @@ -1165,7 +1165,6 @@ A48C95AE2C6A97D80047A056 /* SheetOverlayCoordinator+Reducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A48C95AD2C6A97D80047A056 /* SheetOverlayCoordinator+Reducer.swift */; }; A48C95B02C6A98380047A056 /* SheetOverlayCoordinator+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = A48C95AF2C6A98380047A056 /* SheetOverlayCoordinator+View.swift */; }; A48FD15F2B55E671009295E9 /* TrackedPoolInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A48FD15E2B55E671009295E9 /* TrackedPoolInteraction.swift */; }; - A48FD1612B55F8F0009295E9 /* TransactionReview+Sections.swift in Sources */ = {isa = PBXBuildFile; fileRef = A48FD1602B55F8F0009295E9 /* TransactionReview+Sections.swift */; }; A4A96BB82C7743B200E19CD5 /* InfoButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4A96BB72C7743B200E19CD5 /* InfoButton.swift */; }; A4B017F72B4C099D00B42B8E /* TransactionReview+DepositSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4B017F42B4BF59000B42B8E /* TransactionReview+DepositSettingView.swift */; }; A4CFB55D2BA8CA3200778BDD /* TransactionHistory+TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4CFB55C2BA8CA3200778BDD /* TransactionHistory+TableView.swift */; }; @@ -1960,16 +1959,16 @@ 5B272DD82C36E93100B74F1F /* AppEventsClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppEventsClient+Live.swift"; sourceTree = ""; }; 5B272DDA2C36E9D300B74F1F /* AppEventsClient+Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppEventsClient+Test.swift"; sourceTree = ""; }; 5B27FBD82CC67655002975BE /* HeadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadingView.swift; sourceTree = ""; }; - 5B27FBDF2CC6CCBE002975BE /* Sections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sections.swift; sourceTree = ""; }; + 5B27FBDF2CC6CCBE002975BE /* Sections+Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sections+Data.swift"; sourceTree = ""; }; 5B27FBE92CC70C9D002975BE /* ValidatorsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorsView.swift; sourceTree = ""; }; 5B27FBEB2CC70E87002975BE /* ExpandableHeadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExpandableHeadingView.swift; sourceTree = ""; }; 5B27FBED2CC70F2D002975BE /* InteractionReview+Typealias.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InteractionReview+Typealias.swift"; sourceTree = ""; }; 5B27FBEF2CC70F57002975BE /* Kind.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Kind.swift; sourceTree = ""; }; 5B27FBF42CC713B5002975BE /* UnknownDappComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnknownDappComponents.swift; sourceTree = ""; }; - 5B27FBFB2CC7E6C1002975BE /* MiddleSections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MiddleSections.swift; sourceTree = ""; }; - 5B27FBFC2CC7E6C1002975BE /* MiddleSections+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MiddleSections+View.swift"; sourceTree = ""; }; - 5B27FBFF2CC7E77B002975BE /* MiddleSections+ExecutionSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MiddleSections+ExecutionSummary.swift"; sourceTree = ""; }; - 5B27FC012CC7ECC2002975BE /* MiddleSections+Simulate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MiddleSections+Simulate.swift"; sourceTree = ""; }; + 5B27FBFB2CC7E6C1002975BE /* Sections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sections.swift; sourceTree = ""; }; + 5B27FBFC2CC7E6C1002975BE /* Sections+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sections+View.swift"; sourceTree = ""; }; + 5B27FBFF2CC7E77B002975BE /* Sections+ExecutionSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sections+ExecutionSummary.swift"; sourceTree = ""; }; + 5B27FC012CC7ECC2002975BE /* Sections+Simulate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sections+Simulate.swift"; sourceTree = ""; }; 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactSupportClient.swift; sourceTree = ""; }; 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactSupportClient+Live.swift"; sourceTree = ""; }; 5B3C48A82C7E190C00DB160D /* AssetRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetRow.swift; sourceTree = ""; }; @@ -2401,7 +2400,6 @@ A48C95AD2C6A97D80047A056 /* SheetOverlayCoordinator+Reducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SheetOverlayCoordinator+Reducer.swift"; sourceTree = ""; }; A48C95AF2C6A98380047A056 /* SheetOverlayCoordinator+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SheetOverlayCoordinator+View.swift"; sourceTree = ""; }; A48FD15E2B55E671009295E9 /* TrackedPoolInteraction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackedPoolInteraction.swift; sourceTree = ""; }; - A48FD1602B55F8F0009295E9 /* TransactionReview+Sections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TransactionReview+Sections.swift"; sourceTree = ""; }; A4A1379A2BE4630200D84B50 /* RadixWalletDebug-PreAlpha.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "RadixWalletDebug-PreAlpha.entitlements"; sourceTree = ""; }; A4A96BB72C7743B200E19CD5 /* InfoButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoButton.swift; sourceTree = ""; }; A4B017F42B4BF59000B42B8E /* TransactionReview+DepositSettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TransactionReview+DepositSettingView.swift"; sourceTree = ""; }; @@ -3017,7 +3015,6 @@ children = ( 48CFBCD42ADC10D800E77A5C /* TransactionReview.swift */, 48CFBCF52ADC10D800E77A5C /* TransactionReview+View.swift */, - A48FD1602B55F8F0009295E9 /* TransactionReview+Sections.swift */, A48FD15E2B55E671009295E9 /* TrackedPoolInteraction.swift */, A4EB37C72B6272F3003FE31D /* TrackedValidatorInteraction.swift */, 48CFBCD12ADC10D800E77A5C /* SelectFeePayer */, @@ -5519,11 +5516,11 @@ 5B27FBDE2CC6CCA6002975BE /* Sections */ = { isa = PBXGroup; children = ( - 5B27FBDF2CC6CCBE002975BE /* Sections.swift */, - 5B27FBFB2CC7E6C1002975BE /* MiddleSections.swift */, - 5B27FBFC2CC7E6C1002975BE /* MiddleSections+View.swift */, - 5B27FBFF2CC7E77B002975BE /* MiddleSections+ExecutionSummary.swift */, - 5B27FC012CC7ECC2002975BE /* MiddleSections+Simulate.swift */, + 5B27FBFB2CC7E6C1002975BE /* Sections.swift */, + 5B27FBFC2CC7E6C1002975BE /* Sections+View.swift */, + 5B27FBDF2CC6CCBE002975BE /* Sections+Data.swift */, + 5B27FBFF2CC7E77B002975BE /* Sections+ExecutionSummary.swift */, + 5B27FC012CC7ECC2002975BE /* Sections+Simulate.swift */, 48CFBCE42ADC10D800E77A5C /* Accounts */, 48CFBCDE2ADC10D800E77A5C /* Proofs */, 5B27FBF62CC716BC002975BE /* Dapps */, @@ -7315,7 +7312,7 @@ A4ECE2722BEEAFFC00468BF6 /* SecurityCenterClient+Interface.swift in Sources */, 48CFC2A62ADC10D900E77A5C /* PersonaDetails.swift in Sources */, A40815C12C7E0D08005E65B9 /* NonFungibleIdsCollection.swift in Sources */, - 5B27FBE02CC6CCBE002975BE /* Sections.swift in Sources */, + 5B27FBE02CC6CCBE002975BE /* Sections+Data.swift in Sources */, 83D663B02B271D0100D1AB9E /* TruncationMask.swift in Sources */, 48CFC3462ADC10D900E77A5C /* Completion.swift in Sources */, A40816002C7E0D08005E65B9 /* StateAccountLockersTouchedAtResponse.swift in Sources */, @@ -7407,7 +7404,7 @@ 48CFC2A42ADC10D900E77A5C /* PersonaList+Reducer.swift in Sources */, 48CFC5AA2ADC10DA00E77A5C /* PrimaryRectangularButtonStyle.swift in Sources */, 48CFC29F2ADC10D900E77A5C /* PersonasCoordinator+View.swift in Sources */, - 5B27FC002CC7E783002975BE /* MiddleSections+ExecutionSummary.swift in Sources */, + 5B27FC002CC7E783002975BE /* Sections+ExecutionSummary.swift in Sources */, 48CFC43E2ADC10DA00E77A5C /* FactorSourcesClient+Interface.swift in Sources */, 48CFC4062ADC10DA00E77A5C /* JSONValue.swift in Sources */, 48CFC5812ADC10DA00E77A5C /* URLFormatterClient+Test.swift in Sources */, @@ -7479,7 +7476,6 @@ 48CFC3A42ADC10D900E77A5C /* VersionedAlgorithm.swift in Sources */, A462B5C12B95210000C26D20 /* TransactionHistoryFilters+Reducer.swift in Sources */, A408159C2C7E0D08005E65B9 /* MetadataPublicKeyArrayValue.swift in Sources */, - A48FD1612B55F8F0009295E9 /* TransactionReview+Sections.swift in Sources */, A40816092C7E0D08005E65B9 /* StateEntityDetailsResponseFungibleVaultDetails.swift in Sources */, 48CFC3352ADC10D900E77A5C /* PreviewOfSomeFeatureReducer.swift in Sources */, 48CFC4212ADC10DA00E77A5C /* Swift.DecodingError+Equatable.swift in Sources */, @@ -7971,8 +7967,8 @@ 48CFC4182ADC10DA00E77A5C /* IdentifiedArrayOf+Extensions.swift in Sources */, 48CFC3EB2ADC10D900E77A5C /* RTCClients.swift in Sources */, 48CFC4592ADC10DA00E77A5C /* LedgerHardwareWalletClient+Interface.swift in Sources */, - 5B27FBFD2CC7E6C1002975BE /* MiddleSections.swift in Sources */, - 5B27FBFE2CC7E6C1002975BE /* MiddleSections+View.swift in Sources */, + 5B27FBFD2CC7E6C1002975BE /* Sections.swift in Sources */, + 5B27FBFE2CC7E6C1002975BE /* Sections+View.swift in Sources */, E6F460132BDBE56800B122DB /* Stage2MigrateToSargon+RadixConnectModels+Logic.swift in Sources */, 4841614D2BCAD3D400D2B644 /* Stage1MigrateToSargon+MnemonicWithPassphrase.swift in Sources */, 48CFC5A82ADC10DA00E77A5C /* URLButtonStyle.swift in Sources */, @@ -8227,7 +8223,7 @@ 48AF19CE2BB71C1600796130 /* IntoSargon+Bridge.swift in Sources */, 5B9846C02BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift in Sources */, 48CFC3492ADC10D900E77A5C /* PersonaDataPermissionBox.swift in Sources */, - 5B27FC022CC7ECC9002975BE /* MiddleSections+Simulate.swift in Sources */, + 5B27FC022CC7ECC9002975BE /* Sections+Simulate.swift in Sources */, A408164E2C7E0D08005E65B9 /* TransactionStatus.swift in Sources */, 5BBC43A92BBAC6B0005747B1 /* AppTextEditor.swift in Sources */, A41266F12B15579E00EA38E9 /* ManualAccountRecoverySeedPhrase+View.swift in Sources */, diff --git a/RadixWallet/Clients/OnLedgerEntitiesClient/Helpers/OnLedgerEntitiesClient+ComplexTypes.swift b/RadixWallet/Clients/OnLedgerEntitiesClient/Helpers/OnLedgerEntitiesClient+ComplexTypes.swift index 795b8af93e..284758a8bd 100644 --- a/RadixWallet/Clients/OnLedgerEntitiesClient/Helpers/OnLedgerEntitiesClient+ComplexTypes.swift +++ b/RadixWallet/Clients/OnLedgerEntitiesClient/Helpers/OnLedgerEntitiesClient+ComplexTypes.swift @@ -21,8 +21,8 @@ extension OnLedgerEntitiesClient { resourceQuantifier: FungibleResourceIndicator, poolContributions: [some TrackedPoolInteraction] = [] as [TrackedPoolContribution], validatorStakes: [TrackedValidatorStake] = [], - entities: TransactionReview.ResourcesInfo = [:], - resourceAssociatedDapps: TransactionReview.ResourceAssociatedDapps? = nil, + entities: InteractionReview.Sections.ResourcesInfo = [:], + resourceAssociatedDapps: InteractionReview.Sections.ResourceAssociatedDapps? = nil, networkID: NetworkID, defaultDepositGuarantee: Decimal192 = 1 ) async throws -> ResourceBalance { @@ -81,8 +81,8 @@ extension OnLedgerEntitiesClient { _ resource: OnLedgerEntity.Resource, amount: Decimal192, poolContributions: [some TrackedPoolInteraction] = [], - entities: TransactionReview.ResourcesInfo = [:], - resourceAssociatedDapps: TransactionReview.ResourceAssociatedDapps? = nil, + entities: InteractionReview.Sections.ResourcesInfo = [:], + resourceAssociatedDapps: InteractionReview.Sections.ResourceAssociatedDapps? = nil, networkID: NetworkID, guarantee: TransactionGuarantee?, hiddenResources: [ResourceIdentifier] @@ -189,7 +189,7 @@ extension OnLedgerEntitiesClient { // MARK: Non-fungibles func nonFungibleResourceBalances( - _ resourceInfo: TransactionReview.ResourceInfo, + _ resourceInfo: InteractionReview.Sections.ResourceInfo, resourceAddress: ResourceAddress, resourceQuantifier: NonFungibleResourceIndicator, unstakeData: [NonFungibleGlobalId: UnstakeData] = [:], @@ -321,7 +321,7 @@ extension OnLedgerEntitiesClient { } } -extension TransactionReview.ResourceInfo { +extension InteractionReview.Sections.ResourceInfo { var metadata: OnLedgerEntity.Metadata { switch self { case let .left(resource): diff --git a/RadixWallet/Features/InteractionReview/Sections/MiddleSections+ExecutionSummary.swift b/RadixWallet/Features/InteractionReview/Sections/MiddleSections+ExecutionSummary.swift deleted file mode 100644 index 4c599c815c..0000000000 --- a/RadixWallet/Features/InteractionReview/Sections/MiddleSections+ExecutionSummary.swift +++ /dev/null @@ -1,649 +0,0 @@ -extension InteractionReview.MiddleSections { - // Either the resource from ledger or metadata extracted from the TX manifest - typealias ResourceInfo = Either - typealias ResourcesInfo = [ResourceAddress: ResourceInfo] - typealias ResourceAssociatedDapps = [ResourceAddress: OnLedgerEntity.Metadata] - - func sections(for summary: ExecutionSummary, networkID: NetworkID) async throws -> Common.Sections? { - let allWithdrawAddresses = summary.withdrawals.values.flatMap { $0 }.map(\.resourceAddress) - let allDepositAddresses = summary.deposits.values.flatMap { $0 }.map(\.resourceAddress) - - // Pre-populate with all resource addresses from withdraw and deposit. - let allAddresses: IdentifiedArrayOf = Array((allWithdrawAddresses + allDepositAddresses).uniqued()).asIdentified() - - func resourcesInfo(_ resourceAddresses: [ResourceAddress]) async throws -> ResourcesInfo { - var newlyCreatedMetadata = try Dictionary( - keysWithValues: resourceAddresses.compactMap { resourceAddress in - summary.newEntities.metadata[resourceAddress].map { - ( - resourceAddress, - ResourceInfo.right(OnLedgerEntity.Metadata(newlyCreated: $0)) - ) - } - } - ) - - let existingResources = resourceAddresses.filter { - newlyCreatedMetadata[$0] == nil - } - - let existingResourceDetails = try await onLedgerEntitiesClient.getResources(existingResources) - .reduce(into: ResourcesInfo()) { partialResult, next in - partialResult[next.resourceAddress] = .left(next) - } - - newlyCreatedMetadata.append(contentsOf: existingResourceDetails) - - return newlyCreatedMetadata - } - - switch summary.detailedManifestClass { - case nil: - return nil - - case .general, .transfer: - if summary.detailedManifestClass == .general { - guard !summary.deposits.isEmpty || !summary.withdrawals.isEmpty else { return nil } - } - - let resourcesInfo = try await resourcesInfo(allAddresses.elements) - let withdrawals = try await extractWithdrawals( - accountWithdraws: summary.withdrawals, - newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, - entities: resourcesInfo, - networkID: networkID - ) - - let dappAddresses = summary.encounteredAddresses.compactMap { - switch $0 { - case let .component(componentAddress): - componentAddress.isGlobal ? componentAddress.asGeneral : nil - case let .locker(lockerAddress): - lockerAddress.asGeneral - } - } - - let dAppsUsed = try await extractDapps( - addresses: dappAddresses, - unknownTitle: L10n.TransactionReview.unknownComponents - ) - - let deposits = try await extractDeposits( - accountDeposits: summary.deposits, - newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, - entities: resourcesInfo, - networkID: networkID - ) - - let proofs = try await exctractProofs(summary.presentedProofs) - - return Common.Sections( - withdrawals: withdrawals, - dAppsUsed: dAppsUsed, - deposits: deposits, - proofs: proofs - ) - - case let .poolContribution(poolAddresses, poolContributions): - // All resources that are part of the pool - let resourceAddresses = poolContributions.flatMap { Array($0.contributedResources.keys) } - - let allAddresses = allAddresses + resourceAddresses.asIdentified() - let resourcesInfo = try await resourcesInfo(allAddresses.elements) - - let dApps = await extractDappEntities(poolAddresses.map(\.asGeneral)) - - let perPoolUnitDapps = try perPoolUnitDapps(dApps, poolInteractions: poolContributions) - - // Extract Contributing to Pools section - let pools: InteractionReviewPools.State? = try await extractDapps(dApps, unknownTitle: L10n.TransactionReview.unknownPools) - - // Extract Withdrawals section - let withdrawals = try await extractWithdrawals( - accountWithdraws: summary.withdrawals, - newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, - entities: resourcesInfo, - resourceAssociatedDapps: perPoolUnitDapps, - networkID: networkID - ) - - // Extract Deposits section, passing in poolcontributions so that pool units can be updated - let deposits = try await extractDeposits( - accountDeposits: summary.deposits, - newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, - poolContributions: poolContributions.aggregated, - entities: resourcesInfo, - resourceAssociatedDapps: perPoolUnitDapps, - networkID: networkID - ) - - return Common.Sections( - withdrawals: withdrawals, - deposits: deposits, - contributingToPools: pools - ) - - case let .poolRedemption(poolAddresses, poolRedemptions): - // All resources that are part of the pool - let resourceAddresses = poolRedemptions.flatMap { - Array($0.redeemedResources.keys) - } - - let allAddresses = allAddresses + resourceAddresses.asIdentified() - let resourcesInfo = try await resourcesInfo(allAddresses.elements) - - let dApps = await extractDappEntities(poolAddresses.map(\.asGeneral)) - - let perPoolUnitDapps = try perPoolUnitDapps(dApps, poolInteractions: poolRedemptions) - - // Extract Contributing to Pools section - let pools: InteractionReviewPools.State? = try await extractDapps(dApps, unknownTitle: L10n.TransactionReview.unknownPools) - - // Extract Withdrawals section, passing in poolRedemptions so that withdrawn pool units can be updated - let withdrawals = try await extractWithdrawals( - accountWithdraws: summary.withdrawals, - newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, - poolRedemptions: poolRedemptions.aggregated, - entities: resourcesInfo, - resourceAssociatedDapps: perPoolUnitDapps, - networkID: networkID - ) - - // Extract Deposits section - let deposits = try await extractDeposits( - accountDeposits: summary.deposits, - newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, - entities: resourcesInfo, - resourceAssociatedDapps: perPoolUnitDapps, - networkID: networkID - ) - - return Common.Sections( - withdrawals: withdrawals, - deposits: deposits, - redeemingFromPools: pools - ) - - case let .validatorStake(validatorAddresses: validatorAddresses, validatorStakes: validatorStakes): - let resourcesInfo = try await resourcesInfo(allAddresses.elements) - - let withdrawals = try await extractWithdrawals( - accountWithdraws: summary.withdrawals, - newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, - entities: resourcesInfo, - networkID: networkID - ) - - // Extract validators - let stakingToValidators = try await extractValidators(for: validatorAddresses) - - // Extract Deposits section - let deposits = try await extractDeposits( - accountDeposits: summary.deposits, - newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, - validatorStakes: validatorStakes.aggregated, - entities: resourcesInfo, - networkID: networkID - ) - - return Common.Sections( - withdrawals: withdrawals, - deposits: deposits, - stakingToValidators: stakingToValidators - ) - - case let .validatorUnstake(validatorAddresses, claimsNonFungibleData): - let resourcesInfo = try await resourcesInfo(allAddresses.elements) - - let withdrawals = try await extractWithdrawals( - accountWithdraws: summary.withdrawals, - newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, - entities: resourcesInfo, - networkID: networkID - ) - - // Extract validators - let unstakingFromValidators = try await extractValidators(for: validatorAddresses) - - // Extract Deposits section - let deposits = try await extractDeposits( - accountDeposits: summary.deposits, - newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, - unstakeData: claimsNonFungibleData, - entities: resourcesInfo, - networkID: networkID - ) - - return Common.Sections( - withdrawals: withdrawals, - deposits: deposits, - unstakingFromValidators: unstakingFromValidators - ) - - case let .validatorClaim(validatorAddresses, _): - let resourcesInfo = try await resourcesInfo(allAddresses.elements) - let withdrawals = try? await extractWithdrawals( - accountWithdraws: summary.withdrawals.aggregated, - newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, - entities: resourcesInfo, - networkID: networkID - ) - - let claimingFromValidators = try await extractValidators( - for: validatorAddresses - ) - - let deposits = try? await extractDeposits( - accountDeposits: summary.deposits.aggregated, - newlyCreatedNonFungibles: summary.newlyCreatedNonFungibles, - entities: resourcesInfo, - networkID: networkID - ) - - return Common.Sections( - withdrawals: withdrawals, - deposits: deposits, - claimingFromValidators: claimingFromValidators - ) - - case let .accountDepositSettingsUpdate( - resourcePreferencesUpdates, - depositModeUpdates, - authorizedDepositorsAdded, - authorizedDepositorsRemoved - ): - - let allAccountAddress = Set(authorizedDepositorsAdded.keys) - .union(authorizedDepositorsRemoved.keys) - .union(depositModeUpdates.keys) - .union(resourcePreferencesUpdates.keys) - - let userAccounts = try await accountsClient.getAccountsOnCurrentNetwork() // TODO: Use general one - - let validAccounts = allAccountAddress.compactMap { address in - userAccounts.first { $0.address == address } - } - - let accountDepositSetting = extractAccountDepositSetting( - for: validAccounts, - defaultDepositRuleChanges: depositModeUpdates - ) - let accountDepositExceptions = try await extractAccountDepositExceptions( - for: validAccounts, - resourcePreferenceChanges: resourcePreferencesUpdates, - authorizedDepositorsAdded: authorizedDepositorsAdded, - authorizedDepositorsRemoved: authorizedDepositorsRemoved - ) - - return Common.Sections( - accountDepositSetting: accountDepositSetting, - accountDepositExceptions: accountDepositExceptions - ) - } - } - - private func extractUserAccounts(_ allAddress: [AccountAddress]) async throws -> [Common.ReviewAccount] { - let userAccounts = try await accountsClient.getAccountsOnCurrentNetwork() - - return allAddress - .map { (address: AccountAddress) in - let userAccount = userAccounts.first { userAccount in - userAccount.address.address == address.address - } - if let userAccount { - return .user(userAccount) - } else { - return .external(address, approved: false) - } - } - } - - private func extractDapps( - addresses: [Address], - unknownTitle: (Int) -> String - ) async throws -> InteractionReviewDapps.State? { - let dApps = await extractDappEntities(addresses) - return try await extractDapps(dApps, unknownTitle: unknownTitle) - } - - private func extractDapps( - _ dAppEntities: [(address: Address, entity: InteractionReview.DappEntity?)], - unknownTitle: (Int) -> String - ) async throws -> InteractionReviewDapps.State? { - let knownDapps = dAppEntities.compactMap(\.entity).asIdentified() - let unknownDapps = try dAppEntities.filter { $0.entity == nil } - .map { try $0.address.asSpecific(type: A.self) }.asIdentified() - - guard knownDapps.count + unknownDapps.count > 0 else { return nil } - - return .init(knownDapps: knownDapps, unknownDapps: unknownDapps, unknownTitle: unknownTitle) - } - - private func extractDappEntities(_ addresses: [Address]) async -> [(address: Address, entity: InteractionReview.DappEntity?)] { - await addresses.asyncMap { - await (address: $0, entity: try? extractDappEntity($0.asGeneral)) - } - } - - private func extractDappEntity(_ entity: Address) async throws -> InteractionReview.DappEntity { - let dAppDefinitionAddress = try await onLedgerEntitiesClient.getDappDefinitionAddress(entity) - let metadata = try await onLedgerEntitiesClient.getDappMetadata(dAppDefinitionAddress, validatingDappEntity: entity) - return .init(id: dAppDefinitionAddress, metadata: metadata) - } - - private func exctractProofs(_ accountProofs: [ResourceSpecifier]) async throws -> Common.Proofs.State? { - let proofs = try await accountProofs - .uniqued() - .asyncMap(extractResourceBalanceInfo) - .flatMap { $0 } - .asyncMap(extractProofInfo) - - guard !proofs.isEmpty else { return nil } - - return Common.Proofs.State(kind: .transaction, proofs: proofs.asIdentified()) - } - - private func extractResourceBalanceInfo(specifier: ResourceSpecifier) async throws -> [(ResourceAddress, ResourceBalance.Details)] { - switch specifier { - case let .fungible(resourceAddress, amount): - return [( - resourceAddress, - .fungible( - .init( - isXRD: resourceAddress.isXRD, - amount: .init(nominalAmount: amount) - ) - ) - )] - case let .nonFungible(resourceAddress, ids): - let globalIds = ids.map { NonFungibleGlobalId(resourceAddress: resourceAddress, nonFungibleLocalId: $0) } - let tokens = try await onLedgerEntitiesClient.getNonFungibleTokenData( - .init(resource: resourceAddress, nonFungibleIds: globalIds) - ) - return tokens.map { (resourceAddress, .nonFungible($0)) } - } - } - - private func extractProofInfo(resourceAddress: ResourceAddress, details: ResourceBalance.Details) async throws -> Common.ProofEntity { - try await Common.ProofEntity( - resourceBalance: ResourceBalance( - resource: onLedgerEntitiesClient.getResource(resourceAddress, metadataKeys: .dappMetadataKeys), - details: details - ) - ) - } - - private func extractWithdrawals( - accountWithdraws: [AccountAddress: [ResourceIndicator]], - newlyCreatedNonFungibles: [NonFungibleGlobalId] = [], - poolRedemptions: [TrackedPoolRedemption] = [], - entities: ResourcesInfo = [:], - resourceAssociatedDapps: ResourceAssociatedDapps? = nil, - networkID: NetworkID - ) async throws -> Common.Accounts.State? { - var withdrawals: [Common.ReviewAccount: IdentifiedArrayOf] = [:] - let userAccounts: [Common.ReviewAccount] = try await extractUserAccounts(Array(accountWithdraws.keys)) - - for (accountAddress, resources) in accountWithdraws { - let account = try userAccounts.account(for: accountAddress) - let transfers = try await resources.asyncFlatMap { - try await transferInfo( - resourceQuantifier: $0, - newlyCreatedNonFungibles: newlyCreatedNonFungibles, - poolInteractions: poolRedemptions, - entities: entities, - resourceAssociatedDapps: resourceAssociatedDapps, - networkID: networkID, - type: .exact - ) - } - .map(\.asIdentified) - - withdrawals[account, default: []].append(contentsOf: transfers) - } - - guard !withdrawals.isEmpty else { return nil } - - let withdrawalAccounts = withdrawals.map { - Common.Account.State(account: $0.key, transfers: $0.value, isDeposit: false) - } - .asIdentified() - - return .init(accounts: withdrawalAccounts, enableCustomizeGuarantees: false) - } - - private func extractDeposits( - accountDeposits: [AccountAddress: [ResourceIndicator]], - newlyCreatedNonFungibles: [NonFungibleGlobalId] = [], - poolContributions: [TrackedPoolContribution] = [], - validatorStakes: [TrackedValidatorStake] = [], - unstakeData: [NonFungibleGlobalId: UnstakeData] = [:], - entities: ResourcesInfo = [:], - resourceAssociatedDapps: ResourceAssociatedDapps? = nil, - networkID: NetworkID - ) async throws -> Common.Accounts.State? { - let userAccounts: [Common.ReviewAccount] = try await extractUserAccounts(Array(accountDeposits.keys)) - let defaultDepositGuarantee = await appPreferencesClient.getPreferences().transaction.defaultDepositGuarantee - - var deposits: [Common.ReviewAccount: IdentifiedArrayOf] = [:] - - for (accountAddress, accountDeposits) in accountDeposits { - let account = try userAccounts.account(for: accountAddress) - let transfers = try await accountDeposits.asyncFlatMap { - let aux = try await transferInfo( - resourceQuantifier: $0, - newlyCreatedNonFungibles: newlyCreatedNonFungibles, - poolInteractions: poolContributions, - validatorStakes: validatorStakes, - unstakeData: unstakeData, - entities: entities, - resourceAssociatedDapps: resourceAssociatedDapps, - networkID: networkID, - type: $0.transferType, - defaultDepositGuarantee: defaultDepositGuarantee - ) - return aux - } - .map(\.asIdentified) - - deposits[account, default: []].append(contentsOf: transfers) - } - - let depositAccounts = deposits - .filter { !$0.value.isEmpty } - .map { Common.Account.State(account: $0.key, transfers: $0.value, isDeposit: true) } - .asIdentified() - - guard !depositAccounts.isEmpty else { return nil } - - let requiresGuarantees = !depositAccounts.customizableGuarantees.isEmpty - return .init(accounts: depositAccounts, enableCustomizeGuarantees: requiresGuarantees) - } - - func extractValidators(for addresses: [ValidatorAddress]) async throws -> Common.ValidatorsState? { - guard !addresses.isEmpty else { return nil } - - let validators = try await onLedgerEntitiesClient.getEntities( - addresses: addresses.map(\.asGeneral), - metadataKeys: .resourceMetadataKeys - ) - - .compactMap { entity -> Common.ValidatorState? in - guard let validator = entity.validator else { return nil } - return .init( - address: validator.address, - name: validator.metadata.name, - thumbnail: validator.metadata.iconURL - ) - } - - guard validators.count == addresses.count else { - struct FailedToExtractValidatorInformation: Error {} - throw FailedToExtractValidatorInformation() - } - - return .init(validators: validators) - } - - func extractAccountDepositSetting( - for validAccounts: [Account], - defaultDepositRuleChanges: [AccountAddress: AccountDefaultDepositRule] - ) -> TransactionReview.DepositSettingState? { - let depositSettingChanges: [TransactionReview.DepositSettingChange] = validAccounts.compactMap { account in - guard let depositRuleChange = defaultDepositRuleChanges[account.address] else { return nil } - return .init(account: account, ruleChange: depositRuleChange) - } - - guard !depositSettingChanges.isEmpty else { return nil } - - return .init(changes: IdentifiedArray(uncheckedUniqueElements: depositSettingChanges)) - } - - func extractAccountDepositExceptions( - for validAccounts: [Account], - resourcePreferenceChanges: [AccountAddress: [ResourceAddress: ResourcePreferenceUpdate]], - authorizedDepositorsAdded: [AccountAddress: [ResourceOrNonFungible]], - authorizedDepositorsRemoved: [AccountAddress: [ResourceOrNonFungible]] - ) async throws -> TransactionReview.DepositExceptionsState? { - let exceptionChanges: [TransactionReview.DepositExceptionsChange] = try await validAccounts.asyncCompactMap { account in - let resourcePreferenceChanges = try await resourcePreferenceChanges[account.address]? - .asyncMap { resourcePreference in - try await TransactionReview.DepositExceptionsChange.ResourcePreferenceChange( - resource: onLedgerEntitiesClient.getResource(resourcePreference.key), - change: resourcePreference.value - ) - } ?? [] - - let authorizedDepositorChanges = try await { - var changes: [TransactionReview.DepositExceptionsChange.AllowedDepositorChange] = [] - if let authorizedDepositorsAdded = authorizedDepositorsAdded[account.address] { - let added = try await authorizedDepositorsAdded.asyncMap { resourceOrNonFungible in - let resourceAddress = resourceOrNonFungible.resourceAddress - return try await TransactionReview.DepositExceptionsChange.AllowedDepositorChange( - resource: onLedgerEntitiesClient.getResource(resourceAddress), - change: .added - ) - } - changes.append(contentsOf: added) - } - if let authorizedDepositorsRemoved = authorizedDepositorsRemoved[account.address] { - let removed = try await authorizedDepositorsRemoved.asyncMap { resourceOrNonFungible in - let resourceAddress = resourceOrNonFungible.resourceAddress - return try await TransactionReview.DepositExceptionsChange.AllowedDepositorChange( - resource: onLedgerEntitiesClient.getResource(resourceAddress), - change: .removed - ) - } - changes.append(contentsOf: removed) - } - - return changes - }() - - guard !resourcePreferenceChanges.isEmpty || !authorizedDepositorChanges.isEmpty else { return nil } - - return TransactionReview.DepositExceptionsChange( - account: account, - resourcePreferenceChanges: IdentifiedArray(uncheckedUniqueElements: resourcePreferenceChanges), - allowedDepositorChanges: IdentifiedArray(uncheckedUniqueElements: authorizedDepositorChanges) - ) - } - - guard !exceptionChanges.isEmpty else { return nil } - - return .init(changes: IdentifiedArray(uncheckedUniqueElements: exceptionChanges)) - } - - private func perPoolUnitDapps( - _ dappEntities: [(address: Address, entity: InteractionReview.DappEntity?)], - poolInteractions: [some TrackedPoolInteraction] - ) throws -> ResourceAssociatedDapps { - try Dictionary(keysWithValues: dappEntities.compactMap { data -> (ResourceAddress, OnLedgerEntity.Metadata)? in - let poolUnitResource: ResourceAddress? = poolInteractions - .first(where: { $0.poolAddress.asGeneral == data.address })? - .poolUnitsResourceAddress - - guard let poolUnitResource, - let dAppMetadata = data.entity?.metadata - else { - return nil - } - - return (poolUnitResource, dAppMetadata) - }) - } -} - -extension InteractionReview.MiddleSections { - struct ResourceEntityNotFound: Error { - let address: String - } - - struct FailedToGetDataForAllNFTs: Error {} - struct FailedToGetPoolUnitDetails: Error {} - struct StakeUnitAddressMismatch: Error {} - struct MissingTrackedValidatorStake: Error {} - struct MissingPositiveTotalSupply: Error {} - struct InvalidStakeClaimToken: Error {} - struct MissingStakeClaimTokenData: Error {} - - func transferInfo( - resourceQuantifier: ResourceIndicator, - newlyCreatedNonFungibles: [NonFungibleGlobalId] = [], - poolInteractions: [some TrackedPoolInteraction] = [], - validatorStakes: [TrackedValidatorStake] = [], - unstakeData: [NonFungibleGlobalId: UnstakeData] = [:], - entities: ResourcesInfo = [:], - resourceAssociatedDapps: ResourceAssociatedDapps? = nil, - networkID: NetworkID, - type: TransactionReview.TransferType, - defaultDepositGuarantee: Decimal192 = 1 - ) async throws -> [ResourceBalance] { - let resourceAddress: ResourceAddress = resourceQuantifier.resourceAddress - - guard let resourceInfo = entities[resourceAddress] else { - throw ResourceEntityNotFound(address: resourceAddress.address) - } - - switch resourceQuantifier { - case let .fungible(_, source): - switch resourceInfo { - case let .left(resource): - return try await [onLedgerEntitiesClient.fungibleResourceBalance( - resource, - resourceQuantifier: source, - poolContributions: poolInteractions, - validatorStakes: validatorStakes, - entities: entities, - resourceAssociatedDapps: resourceAssociatedDapps, - networkID: networkID, - defaultDepositGuarantee: defaultDepositGuarantee - )] - case let .right(newEntityMetadata): - // A newly created fungible resource - - let resource: OnLedgerEntity.Resource = .init( - resourceAddress: resourceAddress, - metadata: newEntityMetadata - ) - - let details: ResourceBalance.Fungible = .init( - isXRD: false, - amount: .init(nominalAmount: source.amount), - guarantee: nil - ) - - return [.init(resource: resource, details: .fungible(details), isHidden: false)] - } - - case let .nonFungible(_, indicator): - return try await onLedgerEntitiesClient.nonFungibleResourceBalances( - resourceInfo, - resourceAddress: resourceAddress, - resourceQuantifier: indicator, - unstakeData: unstakeData, - newlyCreatedNonFungibles: newlyCreatedNonFungibles - ) - } - } -} diff --git a/RadixWallet/Features/InteractionReview/Sections/MiddleSections.swift b/RadixWallet/Features/InteractionReview/Sections/MiddleSections.swift deleted file mode 100644 index 43c93af3ff..0000000000 --- a/RadixWallet/Features/InteractionReview/Sections/MiddleSections.swift +++ /dev/null @@ -1,283 +0,0 @@ -// MARK: - InteractionReview.MiddleSections -extension InteractionReview { - @Reducer - struct MiddleSections: Sendable, FeatureReducer { - typealias Common = InteractionReview - - @ObservableState - struct State: Sendable, Hashable { - var withdrawals: Accounts.State? = nil - var dAppsUsed: InteractionReviewDappsUsed.State? = nil - var deposits: Accounts.State? = nil - - var contributingToPools: InteractionReviewPools.State? = nil - var redeemingFromPools: InteractionReviewPools.State? = nil - - var stakingToValidators: InteractionReview.ValidatorsState? = nil - var unstakingFromValidators: InteractionReview.ValidatorsState? = nil - var claimingFromValidators: InteractionReview.ValidatorsState? = nil - - var accountDepositSetting: TransactionReview.DepositSettingState? = nil - var accountDepositExceptions: TransactionReview.DepositExceptionsState? = nil - - // The proofs are set here (within the resolve logic) but should be rendered and handled by the parent view, since they may be placed outside the Sections. - var proofs: Proofs.State? = nil - - @Presents - var destination: Destination.State? = nil - } - - typealias Action = FeatureAction - - enum ViewAction: Sendable, Equatable { - case appeared - } - - enum InternalAction: Sendable, Equatable { - case resolveExecutionSummary(ExecutionSummary, NetworkID) - case simulate - case setSections(Common.Sections?) - } - - @CasePathable - enum ChildAction: Sendable, Equatable { - case withdrawals(Common.Accounts.Action) - case deposits(Common.Accounts.Action) - case dAppsUsed(InteractionReviewDappsUsed.Action) - case contributingToPools(InteractionReviewPools.Action) - case redeemingFromPools(InteractionReviewPools.Action) - } - - enum DelegateAction: Sendable, Hashable { - case failedToResolveSections - case showCustomizeGuarantees([TransactionReviewGuarantee.State]) - } - - struct Destination: DestinationReducer { - @CasePathable - enum State: Sendable, Hashable { - case dApp(DappDetails.State) - case fungibleTokenDetails(FungibleTokenDetails.State) - case nonFungibleTokenDetails(NonFungibleTokenDetails.State) - case poolUnitDetails(PoolUnitDetails.State) - case lsuDetails(LSUDetails.State) - case unknownDappComponents(Common.UnknownDappComponents.State) - case rawTransactionAlert(AlertState) - } - - @CasePathable - enum Action: Sendable, Equatable { - case dApp(DappDetails.Action) - case fungibleTokenDetails(FungibleTokenDetails.Action) - case nonFungibleTokenDetails(NonFungibleTokenDetails.Action) - case lsuDetails(LSUDetails.Action) - case poolUnitDetails(PoolUnitDetails.Action) - case unknownDappComponents(Common.UnknownDappComponents.Action) - case rawTransactionAlert(RawTransactionAlert) - - enum RawTransactionAlert: Sendable, Equatable { - case continueTapped - } - } - - var body: some ReducerOf { - Scope(state: \.dApp, action: \.dApp) { - DappDetails() - } - Scope(state: \.fungibleTokenDetails, action: \.fungibleTokenDetails) { - FungibleTokenDetails() - } - Scope(state: \.nonFungibleTokenDetails, action: \.nonFungibleTokenDetails) { - NonFungibleTokenDetails() - } - Scope(state: \.poolUnitDetails, action: \.poolUnitDetails) { - PoolUnitDetails() - } - Scope(state: \.lsuDetails, action: \.lsuDetails) { - LSUDetails() - } - Scope(state: \.unknownDappComponents, action: \.unknownDappComponents) { - Common.UnknownDappComponents() - } - } - } - - @Dependency(\.onLedgerEntitiesClient) var onLedgerEntitiesClient - @Dependency(\.accountsClient) var accountsClient - @Dependency(\.appPreferencesClient) var appPreferencesClient - - var body: some ReducerOf { - Reduce(core) - .ifLet(\.withdrawals, action: \.child.withdrawals) { - Common.Accounts() - } - .ifLet(\.deposits, action: \.child.deposits) { - Common.Accounts() - } - .ifLet(\.dAppsUsed, action: \.child.dAppsUsed) { - InteractionReviewDappsUsed() - } - .ifLet(\.contributingToPools, action: \.child.contributingToPools) { - InteractionReviewPools() - } - .ifLet(\.redeemingFromPools, action: \.child.redeemingFromPools) { - InteractionReviewPools() - } - .ifLet(destinationPath, action: /Action.destination) { - Destination() - } - } - - private let destinationPath: WritableKeyPath> = \.$destination - - func reduce(into state: inout State, viewAction: ViewAction) -> Effect { - switch viewAction { - case .appeared: - .none - } - } - - func reduce(into state: inout State, internalAction: InternalAction) -> Effect { - switch internalAction { - case let .resolveExecutionSummary(executionSummary, networkID): - return .run { send in - let sections = try await sections(for: executionSummary, networkID: networkID) - await send(.internal(.setSections(sections))) - } catch: { error, send in - loggerGlobal.error("Failed to extract sections from ExecutionSummary, error: \(error)") - await send(.internal(.setSections(nil))) - } - - case .simulate: - return .run { send in - let sections = try await simulateSections() - await send(.internal(.setSections(sections))) - } catch: { error, send in - loggerGlobal.error("Failed to extract sections, error: \(error)") - await send(.internal(.setSections(nil))) - } - - case let .setSections(sections): - guard let sections else { - state.destination = .rawTransactionAlert(.rawTransaction) - return .send(.delegate(.failedToResolveSections)) - } - state.withdrawals = sections.withdrawals - state.dAppsUsed = sections.dAppsUsed - state.contributingToPools = sections.contributingToPools - state.redeemingFromPools = sections.redeemingFromPools - state.stakingToValidators = sections.stakingToValidators - state.unstakingFromValidators = sections.unstakingFromValidators - state.claimingFromValidators = sections.claimingFromValidators - state.deposits = sections.deposits - state.accountDepositSetting = sections.accountDepositSetting - state.accountDepositExceptions = sections.accountDepositExceptions - state.proofs = sections.proofs - return .none - } - } - - func reduce(into state: inout State, childAction: ChildAction) -> Effect { - switch childAction { - case let .withdrawals(.delegate(.showAsset(transfer, token))), - let .deposits(.delegate(.showAsset(transfer, token))): - return resourceDetailsEffect(state: &state, resource: transfer.resource, details: transfer.details, nft: token) - - case let .dAppsUsed(.delegate(.openDapp(dAppID))), let .contributingToPools(.delegate(.openDapp(dAppID))), let .redeemingFromPools(.delegate(.openDapp(dAppID))): - state.destination = .dApp(.init(dAppDefinitionAddress: dAppID)) - return .none - - case let .dAppsUsed(.delegate(.openUnknownAddresses(components))): - state.destination = .unknownDappComponents(.init( - title: L10n.TransactionReview.unknownComponents(components.count), - rowHeading: L10n.Common.component, - addresses: components.map { .component($0) } - )) - return .none - - case let .contributingToPools(.delegate(.openUnknownAddresses(pools))), let .redeemingFromPools(.delegate(.openUnknownAddresses(pools))): - state.destination = .unknownDappComponents(.init( - title: L10n.TransactionReview.unknownPools(pools.count), - rowHeading: L10n.Common.pool, - addresses: pools.map { .resourcePool($0) } - )) - return .none - - case .deposits(.delegate(.showCustomizeGuarantees)): - guard let guarantees = state.deposits?.accounts.customizableGuarantees, !guarantees.isEmpty else { return .none } - return .send(.delegate(.showCustomizeGuarantees(guarantees))) - - default: - return .none - } - } - } -} - -private extension InteractionReview.MiddleSections { - func resourceDetailsEffect( - state: inout State, - resource: OnLedgerEntity.Resource, - details: ResourceBalance.Details, - nft: OnLedgerEntity.NonFungibleToken? = nil - ) -> Effect { - switch details { - case let .fungible(details): - state.destination = .fungibleTokenDetails(.init( - resourceAddress: resource.resourceAddress, - resource: .success(resource), - ownedFungibleResource: .init( - resourceAddress: resource.resourceAddress, - atLedgerState: resource.atLedgerState, - amount: details.amount, - metadata: resource.metadata - ), - isXRD: details.isXRD - )) - - case let .nonFungible(details): - state.destination = .nonFungibleTokenDetails(.init( - resourceAddress: resource.resourceAddress, - resourceDetails: .success(resource), - token: details, - ledgerState: resource.atLedgerState - )) - - case let .liquidStakeUnit(details): - state.destination = .lsuDetails(.init( - validator: details.validator, - stakeUnitResource: .init(resource: details.resource, amount: .init(nominalAmount: details.amount)), - xrdRedemptionValue: details.worth - )) - - case let .poolUnit(details): - state.destination = .poolUnitDetails(.init(resourcesDetails: details.details)) - - case let .stakeClaimNFT(details): - state.destination = .nonFungibleTokenDetails(.init( - resourceAddress: resource.resourceAddress, - resourceDetails: .success(resource), - token: nft, - ledgerState: resource.atLedgerState, - stakeClaim: details.stakeClaimTokens.stakeClaims.first, - isClaimStakeEnabled: false - )) - } - - return .none - } -} - -extension AlertState { - static var rawTransaction: AlertState { - AlertState { - TextState(L10n.TransactionReview.NonConformingManifestWarning.title) - } actions: { - ButtonState(action: .continueTapped) { - TextState(L10n.Common.continue) - } - } message: { - TextState(L10n.TransactionReview.NonConformingManifestWarning.message) - } - } -} diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+Data.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+Data.swift new file mode 100644 index 0000000000..7561e20cf0 --- /dev/null +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+Data.swift @@ -0,0 +1,21 @@ +import Foundation + +extension InteractionReview { + struct SectionsData: Sendable, Hashable { + var withdrawals: Accounts.State? = nil + var dAppsUsed: InteractionReviewDappsUsed.State? = nil + var deposits: Accounts.State? = nil + + var contributingToPools: InteractionReviewPools.State? = nil + var redeemingFromPools: InteractionReviewPools.State? = nil + + var stakingToValidators: InteractionReview.ValidatorsState? = nil + var unstakingFromValidators: InteractionReview.ValidatorsState? = nil + var claimingFromValidators: InteractionReview.ValidatorsState? = nil + + var accountDepositSetting: TransactionReview.DepositSettingState? = nil + var accountDepositExceptions: TransactionReview.DepositExceptionsState? = nil + + var proofs: Proofs.State? = nil + } +} diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+ExecutionSummary.swift similarity index 95% rename from RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift rename to RadixWallet/Features/InteractionReview/Sections/Sections+ExecutionSummary.swift index b164f826e1..ba3295b3be 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+Sections.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+ExecutionSummary.swift @@ -1,13 +1,10 @@ -import Foundation -import Sargon - -extension TransactionReview { +extension InteractionReview.Sections { // Either the resource from ledger or metadata extracted from the TX manifest typealias ResourceInfo = Either typealias ResourcesInfo = [ResourceAddress: ResourceInfo] typealias ResourceAssociatedDapps = [ResourceAddress: OnLedgerEntity.Metadata] - func sections(for summary: ExecutionSummary, networkID: NetworkID) async throws -> Common.Sections? { + func sections(for summary: ExecutionSummary, networkID: NetworkID) async throws -> Common.SectionsData? { let allWithdrawAddresses = summary.withdrawals.values.flatMap { $0 }.map(\.resourceAddress) let allDepositAddresses = summary.deposits.values.flatMap { $0 }.map(\.resourceAddress) @@ -80,7 +77,7 @@ extension TransactionReview { let proofs = try await exctractProofs(summary.presentedProofs) - return Common.Sections( + return Common.SectionsData( withdrawals: withdrawals, dAppsUsed: dAppsUsed, deposits: deposits, @@ -120,7 +117,7 @@ extension TransactionReview { networkID: networkID ) - return Common.Sections( + return Common.SectionsData( withdrawals: withdrawals, deposits: deposits, contributingToPools: pools @@ -161,7 +158,7 @@ extension TransactionReview { networkID: networkID ) - return Common.Sections( + return Common.SectionsData( withdrawals: withdrawals, deposits: deposits, redeemingFromPools: pools @@ -189,7 +186,7 @@ extension TransactionReview { networkID: networkID ) - return Common.Sections( + return Common.SectionsData( withdrawals: withdrawals, deposits: deposits, stakingToValidators: stakingToValidators @@ -217,7 +214,7 @@ extension TransactionReview { networkID: networkID ) - return Common.Sections( + return Common.SectionsData( withdrawals: withdrawals, deposits: deposits, unstakingFromValidators: unstakingFromValidators @@ -243,7 +240,7 @@ extension TransactionReview { networkID: networkID ) - return Common.Sections( + return Common.SectionsData( withdrawals: withdrawals, deposits: deposits, claimingFromValidators: claimingFromValidators @@ -278,7 +275,7 @@ extension TransactionReview { authorizedDepositorsRemoved: authorizedDepositorsRemoved ) - return Common.Sections( + return Common.SectionsData( accountDepositSetting: accountDepositSetting, accountDepositExceptions: accountDepositExceptions ) @@ -491,7 +488,7 @@ extension TransactionReview { func extractAccountDepositSetting( for validAccounts: [Account], defaultDepositRuleChanges: [AccountAddress: AccountDefaultDepositRule] - ) -> DepositSettingState? { + ) -> TransactionReview.DepositSettingState? { let depositSettingChanges: [TransactionReview.DepositSettingChange] = validAccounts.compactMap { account in guard let depositRuleChange = defaultDepositRuleChanges[account.address] else { return nil } return .init(account: account, ruleChange: depositRuleChange) @@ -507,22 +504,22 @@ extension TransactionReview { resourcePreferenceChanges: [AccountAddress: [ResourceAddress: ResourcePreferenceUpdate]], authorizedDepositorsAdded: [AccountAddress: [ResourceOrNonFungible]], authorizedDepositorsRemoved: [AccountAddress: [ResourceOrNonFungible]] - ) async throws -> DepositExceptionsState? { - let exceptionChanges: [DepositExceptionsChange] = try await validAccounts.asyncCompactMap { account in + ) async throws -> TransactionReview.DepositExceptionsState? { + let exceptionChanges: [TransactionReview.DepositExceptionsChange] = try await validAccounts.asyncCompactMap { account in let resourcePreferenceChanges = try await resourcePreferenceChanges[account.address]? .asyncMap { resourcePreference in - try await DepositExceptionsChange.ResourcePreferenceChange( + try await TransactionReview.DepositExceptionsChange.ResourcePreferenceChange( resource: onLedgerEntitiesClient.getResource(resourcePreference.key), change: resourcePreference.value ) } ?? [] let authorizedDepositorChanges = try await { - var changes: [DepositExceptionsChange.AllowedDepositorChange] = [] + var changes: [TransactionReview.DepositExceptionsChange.AllowedDepositorChange] = [] if let authorizedDepositorsAdded = authorizedDepositorsAdded[account.address] { let added = try await authorizedDepositorsAdded.asyncMap { resourceOrNonFungible in let resourceAddress = resourceOrNonFungible.resourceAddress - return try await DepositExceptionsChange.AllowedDepositorChange( + return try await TransactionReview.DepositExceptionsChange.AllowedDepositorChange( resource: onLedgerEntitiesClient.getResource(resourceAddress), change: .added ) @@ -532,7 +529,7 @@ extension TransactionReview { if let authorizedDepositorsRemoved = authorizedDepositorsRemoved[account.address] { let removed = try await authorizedDepositorsRemoved.asyncMap { resourceOrNonFungible in let resourceAddress = resourceOrNonFungible.resourceAddress - return try await DepositExceptionsChange.AllowedDepositorChange( + return try await TransactionReview.DepositExceptionsChange.AllowedDepositorChange( resource: onLedgerEntitiesClient.getResource(resourceAddress), change: .removed ) @@ -545,7 +542,7 @@ extension TransactionReview { guard !resourcePreferenceChanges.isEmpty || !authorizedDepositorChanges.isEmpty else { return nil } - return DepositExceptionsChange( + return TransactionReview.DepositExceptionsChange( account: account, resourcePreferenceChanges: IdentifiedArray(uncheckedUniqueElements: resourcePreferenceChanges), allowedDepositorChanges: IdentifiedArray(uncheckedUniqueElements: authorizedDepositorChanges) @@ -554,7 +551,7 @@ extension TransactionReview { guard !exceptionChanges.isEmpty else { return nil } - return DepositExceptionsState(changes: IdentifiedArray(uncheckedUniqueElements: exceptionChanges)) + return .init(changes: IdentifiedArray(uncheckedUniqueElements: exceptionChanges)) } private func perPoolUnitDapps( @@ -577,7 +574,7 @@ extension TransactionReview { } } -extension TransactionReview { +extension InteractionReview.Sections { struct ResourceEntityNotFound: Error { let address: String } @@ -599,7 +596,7 @@ extension TransactionReview { entities: ResourcesInfo = [:], resourceAssociatedDapps: ResourceAssociatedDapps? = nil, networkID: NetworkID, - type: TransferType, + type: TransactionReview.TransferType, defaultDepositGuarantee: Decimal192 = 1 ) async throws -> [ResourceBalance] { let resourceAddress: ResourceAddress = resourceQuantifier.resourceAddress diff --git a/RadixWallet/Features/InteractionReview/Sections/MiddleSections+Simulate.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+Simulate.swift similarity index 91% rename from RadixWallet/Features/InteractionReview/Sections/MiddleSections+Simulate.swift rename to RadixWallet/Features/InteractionReview/Sections/Sections+Simulate.swift index 08b3242b27..8b8b4a1132 100644 --- a/RadixWallet/Features/InteractionReview/Sections/MiddleSections+Simulate.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+Simulate.swift @@ -1,5 +1,5 @@ -extension InteractionReview.MiddleSections { - func simulateSections() async throws -> Common.Sections? { +extension InteractionReview.Sections { + func simulateSections() async throws -> Common.SectionsData? { let xrdBalance: ResourceBalance = .init(resource: .init(resourceAddress: .sampleStokenetXRD, metadata: .init(name: "Radix", symbol: "XRD", isComplete: true)), details: .fungible(.init(isXRD: true, amount: .init(nominalAmount: .five)))) let idResourceBalance = xrdBalance.asIdentified @@ -28,7 +28,7 @@ extension InteractionReview.MiddleSections { .init(resourceBalance: nftBalance), ]) - return Common.Sections( + return Common.SectionsData( withdrawals: withdrawals, deposits: deposits, proofs: proofs diff --git a/RadixWallet/Features/InteractionReview/Sections/MiddleSections+View.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift similarity index 91% rename from RadixWallet/Features/InteractionReview/Sections/MiddleSections+View.swift rename to RadixWallet/Features/InteractionReview/Sections/Sections+View.swift index 672193de46..633da3a3da 100644 --- a/RadixWallet/Features/InteractionReview/Sections/MiddleSections+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift @@ -1,9 +1,9 @@ import SwiftUI -// MARK: - InteractionReview.MiddleSections.View -extension InteractionReview.MiddleSections { +// MARK: - InteractionReview.Sections.View +extension InteractionReview.Sections { struct View: SwiftUI.View { - let store: StoreOf + let store: StoreOf var body: some SwiftUI.View { WithPerceptionTracking { @@ -123,15 +123,15 @@ extension InteractionReview.MiddleSections { } } -extension InteractionReview.MiddleSections.State { +extension InteractionReview.Sections.State { var showTransferLine: Bool { withdrawals != nil && deposits != nil } } -extension StoreOf { - var destination: PresentationStoreOf { - func scopeState(state: State) -> PresentationState { +extension StoreOf { + var destination: PresentationStoreOf { + func scopeState(state: State) -> PresentationState { state.$destination } return scope(state: scopeState, action: Action.destination) @@ -140,9 +140,9 @@ extension StoreOf { @MainActor private extension View { - typealias Destination = InteractionReview.MiddleSections.Destination + typealias Destination = InteractionReview.Sections.Destination - func destinations(with store: StoreOf) -> some View { + func destinations(with store: StoreOf) -> some View { let destinationStore = store.destination return dApp(with: destinationStore) .fungibleTokenDetails(with: destinationStore) diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections.swift b/RadixWallet/Features/InteractionReview/Sections/Sections.swift index e127d7ab32..4706182d16 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections.swift @@ -1,21 +1,283 @@ -import Foundation - +// MARK: - InteractionReview.Sections extension InteractionReview { - struct Sections: Sendable, Hashable { - var withdrawals: Accounts.State? = nil - var dAppsUsed: InteractionReviewDappsUsed.State? = nil - var deposits: Accounts.State? = nil + @Reducer + struct Sections: Sendable, FeatureReducer { + typealias Common = InteractionReview + + @ObservableState + struct State: Sendable, Hashable { + var withdrawals: Accounts.State? = nil + var dAppsUsed: InteractionReviewDappsUsed.State? = nil + var deposits: Accounts.State? = nil + + var contributingToPools: InteractionReviewPools.State? = nil + var redeemingFromPools: InteractionReviewPools.State? = nil + + var stakingToValidators: InteractionReview.ValidatorsState? = nil + var unstakingFromValidators: InteractionReview.ValidatorsState? = nil + var claimingFromValidators: InteractionReview.ValidatorsState? = nil + + var accountDepositSetting: TransactionReview.DepositSettingState? = nil + var accountDepositExceptions: TransactionReview.DepositExceptionsState? = nil + + // The proofs are set here (within the resolve logic) but should be rendered and handled by the parent view, since they may be placed outside the Sections. + var proofs: Proofs.State? = nil + + @Presents + var destination: Destination.State? = nil + } + + typealias Action = FeatureAction + + enum ViewAction: Sendable, Equatable { + case appeared + } + + enum InternalAction: Sendable, Equatable { + case resolveExecutionSummary(ExecutionSummary, NetworkID) + case simulate + case setSections(Common.SectionsData?) + } + + @CasePathable + enum ChildAction: Sendable, Equatable { + case withdrawals(Common.Accounts.Action) + case deposits(Common.Accounts.Action) + case dAppsUsed(InteractionReviewDappsUsed.Action) + case contributingToPools(InteractionReviewPools.Action) + case redeemingFromPools(InteractionReviewPools.Action) + } + + enum DelegateAction: Sendable, Hashable { + case failedToResolveSections + case showCustomizeGuarantees([TransactionReviewGuarantee.State]) + } + + struct Destination: DestinationReducer { + @CasePathable + enum State: Sendable, Hashable { + case dApp(DappDetails.State) + case fungibleTokenDetails(FungibleTokenDetails.State) + case nonFungibleTokenDetails(NonFungibleTokenDetails.State) + case poolUnitDetails(PoolUnitDetails.State) + case lsuDetails(LSUDetails.State) + case unknownDappComponents(Common.UnknownDappComponents.State) + case rawTransactionAlert(AlertState) + } + + @CasePathable + enum Action: Sendable, Equatable { + case dApp(DappDetails.Action) + case fungibleTokenDetails(FungibleTokenDetails.Action) + case nonFungibleTokenDetails(NonFungibleTokenDetails.Action) + case lsuDetails(LSUDetails.Action) + case poolUnitDetails(PoolUnitDetails.Action) + case unknownDappComponents(Common.UnknownDappComponents.Action) + case rawTransactionAlert(RawTransactionAlert) + + enum RawTransactionAlert: Sendable, Equatable { + case continueTapped + } + } + + var body: some ReducerOf { + Scope(state: \.dApp, action: \.dApp) { + DappDetails() + } + Scope(state: \.fungibleTokenDetails, action: \.fungibleTokenDetails) { + FungibleTokenDetails() + } + Scope(state: \.nonFungibleTokenDetails, action: \.nonFungibleTokenDetails) { + NonFungibleTokenDetails() + } + Scope(state: \.poolUnitDetails, action: \.poolUnitDetails) { + PoolUnitDetails() + } + Scope(state: \.lsuDetails, action: \.lsuDetails) { + LSUDetails() + } + Scope(state: \.unknownDappComponents, action: \.unknownDappComponents) { + Common.UnknownDappComponents() + } + } + } + + @Dependency(\.onLedgerEntitiesClient) var onLedgerEntitiesClient + @Dependency(\.accountsClient) var accountsClient + @Dependency(\.appPreferencesClient) var appPreferencesClient + + var body: some ReducerOf { + Reduce(core) + .ifLet(\.withdrawals, action: \.child.withdrawals) { + Common.Accounts() + } + .ifLet(\.deposits, action: \.child.deposits) { + Common.Accounts() + } + .ifLet(\.dAppsUsed, action: \.child.dAppsUsed) { + InteractionReviewDappsUsed() + } + .ifLet(\.contributingToPools, action: \.child.contributingToPools) { + InteractionReviewPools() + } + .ifLet(\.redeemingFromPools, action: \.child.redeemingFromPools) { + InteractionReviewPools() + } + .ifLet(destinationPath, action: /Action.destination) { + Destination() + } + } - var contributingToPools: InteractionReviewPools.State? = nil - var redeemingFromPools: InteractionReviewPools.State? = nil + private let destinationPath: WritableKeyPath> = \.$destination - var stakingToValidators: InteractionReview.ValidatorsState? = nil - var unstakingFromValidators: InteractionReview.ValidatorsState? = nil - var claimingFromValidators: InteractionReview.ValidatorsState? = nil + func reduce(into state: inout State, viewAction: ViewAction) -> Effect { + switch viewAction { + case .appeared: + .none + } + } - var accountDepositSetting: TransactionReview.DepositSettingState? = nil - var accountDepositExceptions: TransactionReview.DepositExceptionsState? = nil + func reduce(into state: inout State, internalAction: InternalAction) -> Effect { + switch internalAction { + case let .resolveExecutionSummary(executionSummary, networkID): + return .run { send in + let sections = try await sections(for: executionSummary, networkID: networkID) + await send(.internal(.setSections(sections))) + } catch: { error, send in + loggerGlobal.error("Failed to extract sections from ExecutionSummary, error: \(error)") + await send(.internal(.setSections(nil))) + } + + case .simulate: + return .run { send in + let sections = try await simulateSections() + await send(.internal(.setSections(sections))) + } catch: { error, send in + loggerGlobal.error("Failed to extract sections, error: \(error)") + await send(.internal(.setSections(nil))) + } + + case let .setSections(sections): + guard let sections else { + state.destination = .rawTransactionAlert(.rawTransaction) + return .send(.delegate(.failedToResolveSections)) + } + state.withdrawals = sections.withdrawals + state.dAppsUsed = sections.dAppsUsed + state.contributingToPools = sections.contributingToPools + state.redeemingFromPools = sections.redeemingFromPools + state.stakingToValidators = sections.stakingToValidators + state.unstakingFromValidators = sections.unstakingFromValidators + state.claimingFromValidators = sections.claimingFromValidators + state.deposits = sections.deposits + state.accountDepositSetting = sections.accountDepositSetting + state.accountDepositExceptions = sections.accountDepositExceptions + state.proofs = sections.proofs + return .none + } + } + + func reduce(into state: inout State, childAction: ChildAction) -> Effect { + switch childAction { + case let .withdrawals(.delegate(.showAsset(transfer, token))), + let .deposits(.delegate(.showAsset(transfer, token))): + return resourceDetailsEffect(state: &state, resource: transfer.resource, details: transfer.details, nft: token) + + case let .dAppsUsed(.delegate(.openDapp(dAppID))), let .contributingToPools(.delegate(.openDapp(dAppID))), let .redeemingFromPools(.delegate(.openDapp(dAppID))): + state.destination = .dApp(.init(dAppDefinitionAddress: dAppID)) + return .none + + case let .dAppsUsed(.delegate(.openUnknownAddresses(components))): + state.destination = .unknownDappComponents(.init( + title: L10n.TransactionReview.unknownComponents(components.count), + rowHeading: L10n.Common.component, + addresses: components.map { .component($0) } + )) + return .none + + case let .contributingToPools(.delegate(.openUnknownAddresses(pools))), let .redeemingFromPools(.delegate(.openUnknownAddresses(pools))): + state.destination = .unknownDappComponents(.init( + title: L10n.TransactionReview.unknownPools(pools.count), + rowHeading: L10n.Common.pool, + addresses: pools.map { .resourcePool($0) } + )) + return .none + + case .deposits(.delegate(.showCustomizeGuarantees)): + guard let guarantees = state.deposits?.accounts.customizableGuarantees, !guarantees.isEmpty else { return .none } + return .send(.delegate(.showCustomizeGuarantees(guarantees))) + + default: + return .none + } + } + } +} + +private extension InteractionReview.Sections { + func resourceDetailsEffect( + state: inout State, + resource: OnLedgerEntity.Resource, + details: ResourceBalance.Details, + nft: OnLedgerEntity.NonFungibleToken? = nil + ) -> Effect { + switch details { + case let .fungible(details): + state.destination = .fungibleTokenDetails(.init( + resourceAddress: resource.resourceAddress, + resource: .success(resource), + ownedFungibleResource: .init( + resourceAddress: resource.resourceAddress, + atLedgerState: resource.atLedgerState, + amount: details.amount, + metadata: resource.metadata + ), + isXRD: details.isXRD + )) + + case let .nonFungible(details): + state.destination = .nonFungibleTokenDetails(.init( + resourceAddress: resource.resourceAddress, + resourceDetails: .success(resource), + token: details, + ledgerState: resource.atLedgerState + )) + + case let .liquidStakeUnit(details): + state.destination = .lsuDetails(.init( + validator: details.validator, + stakeUnitResource: .init(resource: details.resource, amount: .init(nominalAmount: details.amount)), + xrdRedemptionValue: details.worth + )) + + case let .poolUnit(details): + state.destination = .poolUnitDetails(.init(resourcesDetails: details.details)) + + case let .stakeClaimNFT(details): + state.destination = .nonFungibleTokenDetails(.init( + resourceAddress: resource.resourceAddress, + resourceDetails: .success(resource), + token: nft, + ledgerState: resource.atLedgerState, + stakeClaim: details.stakeClaimTokens.stakeClaims.first, + isClaimStakeEnabled: false + )) + } + + return .none + } +} - var proofs: Proofs.State? = nil +extension AlertState { + static var rawTransaction: AlertState { + AlertState { + TextState(L10n.TransactionReview.NonConformingManifestWarning.title) + } actions: { + ButtonState(action: .continueTapped) { + TextState(L10n.Common.continue) + } + } message: { + TextState(L10n.TransactionReview.NonConformingManifestWarning.message) + } } } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index e4e3a46d67..d90847bbe7 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -121,7 +121,7 @@ extension PreAuthorizationReview { private var sections: some SwiftUI.View { let childStore = store.scope(state: \.sections, action: \.child.sections) - return Common.MiddleSections.View(store: childStore) + return Common.Sections.View(store: childStore) } @ViewBuilder diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 1e5cd87785..6437dedb0e 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -14,7 +14,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { var secondsToExpiration: Int? // Sections - var sections: Common.MiddleSections.State = .init() + var sections: Common.Sections.State = .init() var proofs: Common.Proofs.State? = nil init() {} @@ -30,7 +30,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { @CasePathable enum ChildAction: Sendable, Equatable { - case sections(Common.MiddleSections.Action) + case sections(Common.Sections.Action) case proofs(Common.Proofs.Action) } @@ -43,7 +43,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { var body: some ReducerOf { Scope(state: \.sections, action: \.child.sections) { - Common.MiddleSections() + Common.Sections() } Reduce(core) .ifLet(\.proofs, action: \.child.proofs) { diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index 7b69237b9f..acb45ebaf0 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -228,7 +228,7 @@ extension TransactionReview { private var sections: some SwiftUI.View { let childStore = store.scope(state: \.sections, action: \.child.sections) - return Common.MiddleSections.View(store: childStore) + return Common.Sections.View(store: childStore) } private var withdrawalsSection: some SwiftUI.View { diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift index 44d1a70d47..6b06727fa5 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift @@ -21,7 +21,7 @@ struct TransactionReview: Sendable, FeatureReducer { var reviewedTransaction: ReviewedTransaction? = nil - var sections: Common.MiddleSections.State = .init() + var sections: Common.Sections.State = .init() var withdrawals: Common.Accounts.State? = nil var dAppsUsed: InteractionReviewDappsUsed.State? = nil var contributingToPools: InteractionReviewPools.State? = nil @@ -112,7 +112,7 @@ struct TransactionReview: Sendable, FeatureReducer { @CasePathable enum ChildAction: Sendable, Equatable { - case sections(Common.MiddleSections.Action) + case sections(Common.Sections.Action) case withdrawals(Common.Accounts.Action) case deposits(Common.Accounts.Action) case dAppsUsed(InteractionReviewDappsUsed.Action) @@ -124,7 +124,7 @@ struct TransactionReview: Sendable, FeatureReducer { enum InternalAction: Sendable, Equatable { case previewLoaded(TaskResult) - case updateSections(Common.Sections?) + case updateSections(Common.SectionsData?) case buildTransactionIntentResult(TaskResult) case notarizeResult(TaskResult) case determineFeePayerResult(TaskResult) @@ -217,7 +217,7 @@ struct TransactionReview: Sendable, FeatureReducer { var body: some ReducerOf { Scope(state: \.sections, action: \.child.sections) { - Common.MiddleSections() + Common.Sections() } Reduce(core) .ifLet(\.networkFee, action: /Action.child .. ChildAction.networkFee) { From 16560316af1dfb3024845af66e880350052f0b8a Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 22 Oct 2024 13:02:23 -0300 Subject: [PATCH 22/63] move deposit and settings to sections --- RadixWallet.xcodeproj/project.pbxproj | 28 ++++---- .../DepositExceptionsView.swift} | 70 ++++++++++--------- .../DepositSetting/DepositSettingView.swift} | 34 +++++---- .../Sections/Sections+Data.swift | 4 +- .../Sections/Sections+ExecutionSummary.swift | 18 ++--- .../Sections/Sections+View.swift | 30 +++++--- .../InteractionReview/Sections/Sections.swift | 4 +- .../TransactionReview+View.swift | 12 ++-- .../TransactionReview.swift | 4 +- 9 files changed, 112 insertions(+), 92 deletions(-) rename RadixWallet/Features/{TransactionReviewFeature/TransactionReviewDepositExceptions/TransactionReview+DepositExceptionsView.swift => InteractionReview/Sections/DepositExceptions/DepositExceptionsView.swift} (88%) rename RadixWallet/Features/{TransactionReviewFeature/TransactionReviewDepositSetting/TransactionReview+DepositSettingView.swift => InteractionReview/Sections/DepositSetting/DepositSettingView.swift} (71%) diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index 54267c7b46..be964b8452 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -145,7 +145,7 @@ 48CFC29A2ADC10D900E77A5C /* InteractionReviewDapps+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCF32ADC10D800E77A5C /* InteractionReviewDapps+View.swift */; }; 48CFC29B2ADC10D900E77A5C /* InteractionReviewDapps.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCF42ADC10D800E77A5C /* InteractionReviewDapps.swift */; }; 48CFC29C2ADC10D900E77A5C /* TransactionReview+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCF52ADC10D800E77A5C /* TransactionReview+View.swift */; }; - 48CFC29E2ADC10D900E77A5C /* TransactionReview+DepositExceptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCF82ADC10D800E77A5C /* TransactionReview+DepositExceptionsView.swift */; }; + 48CFC29E2ADC10D900E77A5C /* DepositExceptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCF82ADC10D800E77A5C /* DepositExceptionsView.swift */; }; 48CFC29F2ADC10D900E77A5C /* PersonasCoordinator+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCFC2ADC10D800E77A5C /* PersonasCoordinator+View.swift */; }; 48CFC2A02ADC10D900E77A5C /* PersonasCoordinator+Reducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCFD2ADC10D800E77A5C /* PersonasCoordinator+Reducer.swift */; }; 48CFC2A12ADC10D900E77A5C /* PersonaFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBD002ADC10D800E77A5C /* PersonaFeature.swift */; }; @@ -1166,7 +1166,7 @@ A48C95B02C6A98380047A056 /* SheetOverlayCoordinator+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = A48C95AF2C6A98380047A056 /* SheetOverlayCoordinator+View.swift */; }; A48FD15F2B55E671009295E9 /* TrackedPoolInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A48FD15E2B55E671009295E9 /* TrackedPoolInteraction.swift */; }; A4A96BB82C7743B200E19CD5 /* InfoButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4A96BB72C7743B200E19CD5 /* InfoButton.swift */; }; - A4B017F72B4C099D00B42B8E /* TransactionReview+DepositSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4B017F42B4BF59000B42B8E /* TransactionReview+DepositSettingView.swift */; }; + A4B017F72B4C099D00B42B8E /* DepositSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4B017F42B4BF59000B42B8E /* DepositSettingView.swift */; }; A4CFB55D2BA8CA3200778BDD /* TransactionHistory+TableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4CFB55C2BA8CA3200778BDD /* TransactionHistory+TableView.swift */; }; A4CFB55F2BAA821E00778BDD /* HScrollBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4CFB55E2BAA821E00778BDD /* HScrollBar.swift */; }; A4CFB5612BAA826E00778BDD /* Measure+Position.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4CFB5602BAA826E00778BDD /* Measure+Position.swift */; }; @@ -1413,7 +1413,7 @@ 48CFBCF32ADC10D800E77A5C /* InteractionReviewDapps+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "InteractionReviewDapps+View.swift"; sourceTree = ""; }; 48CFBCF42ADC10D800E77A5C /* InteractionReviewDapps.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InteractionReviewDapps.swift; sourceTree = ""; }; 48CFBCF52ADC10D800E77A5C /* TransactionReview+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TransactionReview+View.swift"; sourceTree = ""; }; - 48CFBCF82ADC10D800E77A5C /* TransactionReview+DepositExceptionsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TransactionReview+DepositExceptionsView.swift"; sourceTree = ""; }; + 48CFBCF82ADC10D800E77A5C /* DepositExceptionsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DepositExceptionsView.swift; sourceTree = ""; }; 48CFBCFC2ADC10D800E77A5C /* PersonasCoordinator+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PersonasCoordinator+View.swift"; sourceTree = ""; }; 48CFBCFD2ADC10D800E77A5C /* PersonasCoordinator+Reducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "PersonasCoordinator+Reducer.swift"; sourceTree = ""; }; 48CFBD002ADC10D800E77A5C /* PersonaFeature.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonaFeature.swift; sourceTree = ""; }; @@ -2402,7 +2402,7 @@ A48FD15E2B55E671009295E9 /* TrackedPoolInteraction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackedPoolInteraction.swift; sourceTree = ""; }; A4A1379A2BE4630200D84B50 /* RadixWalletDebug-PreAlpha.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "RadixWalletDebug-PreAlpha.entitlements"; sourceTree = ""; }; A4A96BB72C7743B200E19CD5 /* InfoButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoButton.swift; sourceTree = ""; }; - A4B017F42B4BF59000B42B8E /* TransactionReview+DepositSettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TransactionReview+DepositSettingView.swift"; sourceTree = ""; }; + A4B017F42B4BF59000B42B8E /* DepositSettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepositSettingView.swift; sourceTree = ""; }; A4CFB55C2BA8CA3200778BDD /* TransactionHistory+TableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TransactionHistory+TableView.swift"; sourceTree = ""; }; A4CFB55E2BAA821E00778BDD /* HScrollBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HScrollBar.swift; sourceTree = ""; }; A4CFB5602BAA826E00778BDD /* Measure+Position.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Measure+Position.swift"; sourceTree = ""; }; @@ -3023,8 +3023,6 @@ 48CFBCE12ADC10D800E77A5C /* TransactionReviewRawTransaction */, 48CFBCE72ADC10D800E77A5C /* TransactionReviewNetworkFee */, 48CFBCEA2ADC10D800E77A5C /* CustomizeFees */, - A4B017F32B4BF57B00B42B8E /* TransactionReviewDepositSetting */, - 48CFBCF62ADC10D800E77A5C /* TransactionReviewDepositExceptions */, ); path = TransactionReviewFeature; sourceTree = ""; @@ -3116,12 +3114,12 @@ path = CustomizeFees; sourceTree = ""; }; - 48CFBCF62ADC10D800E77A5C /* TransactionReviewDepositExceptions */ = { + 48CFBCF62ADC10D800E77A5C /* DepositExceptions */ = { isa = PBXGroup; children = ( - 48CFBCF82ADC10D800E77A5C /* TransactionReview+DepositExceptionsView.swift */, + 48CFBCF82ADC10D800E77A5C /* DepositExceptionsView.swift */, ); - path = TransactionReviewDepositExceptions; + path = DepositExceptions; sourceTree = ""; }; 48CFBCF92ADC10D800E77A5C /* DappsAndPersonas */ = { @@ -5524,6 +5522,8 @@ 48CFBCE42ADC10D800E77A5C /* Accounts */, 48CFBCDE2ADC10D800E77A5C /* Proofs */, 5B27FBF62CC716BC002975BE /* Dapps */, + A4B017F32B4BF57B00B42B8E /* DepositSetting */, + 48CFBCF62ADC10D800E77A5C /* DepositExceptions */, ); path = Sections; sourceTree = ""; @@ -6289,12 +6289,12 @@ path = IOSSecurityClient; sourceTree = ""; }; - A4B017F32B4BF57B00B42B8E /* TransactionReviewDepositSetting */ = { + A4B017F32B4BF57B00B42B8E /* DepositSetting */ = { isa = PBXGroup; children = ( - A4B017F42B4BF59000B42B8E /* TransactionReview+DepositSettingView.swift */, + A4B017F42B4BF59000B42B8E /* DepositSettingView.swift */, ); - path = TransactionReviewDepositSetting; + path = DepositSetting; sourceTree = ""; }; A4DBBEB12C20302B00D0A59E /* CardCarousel */ = { @@ -7630,7 +7630,7 @@ A40815542C7E0D08005E65B9 /* AccountAuthorizedDepositorsResponseItem.swift in Sources */, 48CFC3282ADC10D900E77A5C /* ScanQRCoordinator+View.swift in Sources */, 48CFC4122ADC10DA00E77A5C /* ErrorQueue+Interface.swift in Sources */, - A4B017F72B4C099D00B42B8E /* TransactionReview+DepositSettingView.swift in Sources */, + A4B017F72B4C099D00B42B8E /* DepositSettingView.swift in Sources */, A408158A2C7E0D08005E65B9 /* MetadataBoolValue.swift in Sources */, A40815F52C7E0D08005E65B9 /* ResourceHoldersResponse.swift in Sources */, 834B651F2B972E5100B7E1E8 /* NPSSurvey.swift in Sources */, @@ -8056,7 +8056,7 @@ 48CFC5BB2ADC10DA00E77A5C /* PlainListRow.swift in Sources */, 48CFC2AB2ADC10D900E77A5C /* Home.swift in Sources */, 48CFC42F2ADC10DA00E77A5C /* Tagged+Comparable.swift in Sources */, - 48CFC29E2ADC10D900E77A5C /* TransactionReview+DepositExceptionsView.swift in Sources */, + 48CFC29E2ADC10D900E77A5C /* DepositExceptionsView.swift in Sources */, A408164C2C7E0D08005E65B9 /* TransactionPreviewResponseLogsInner.swift in Sources */, 48CFC43C2ADC10DA00E77A5C /* Validation.swift in Sources */, 48CFC36E2ADC10D900E77A5C /* FungibleAssetList+Row+View.swift in Sources */, diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewDepositExceptions/TransactionReview+DepositExceptionsView.swift b/RadixWallet/Features/InteractionReview/Sections/DepositExceptions/DepositExceptionsView.swift similarity index 88% rename from RadixWallet/Features/TransactionReviewFeature/TransactionReviewDepositExceptions/TransactionReview+DepositExceptionsView.swift rename to RadixWallet/Features/InteractionReview/Sections/DepositExceptions/DepositExceptionsView.swift index 14b395a0b0..9346b7ad0f 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewDepositExceptions/TransactionReview+DepositExceptionsView.swift +++ b/RadixWallet/Features/InteractionReview/Sections/DepositExceptions/DepositExceptionsView.swift @@ -1,40 +1,12 @@ import ComposableArchitecture import SwiftUI -extension TransactionReview { - struct DepositExceptionsState: Sendable, Hashable { - var changes: IdentifiedArrayOf - } - - struct DepositExceptionsChange: Sendable, Identifiable, Hashable { - var id: AccountAddress.ID { account.address.id } - let account: Account - let resourcePreferenceChanges: IdentifiedArrayOf - let allowedDepositorChanges: IdentifiedArrayOf - - struct ResourcePreferenceChange: Sendable, Identifiable, Hashable { - var id: OnLedgerEntity.Resource.ID { resource.id } - let resource: OnLedgerEntity.Resource - let change: ResourcePreferenceUpdate - } - - struct AllowedDepositorChange: Sendable, Identifiable, Hashable { - var id: OnLedgerEntity.Resource.ID { resource.id } - let resource: OnLedgerEntity.Resource - let change: Change +extension InteractionReview { + typealias DepositExceptionsState = DepositExceptionsView.ViewState + typealias DepositExceptionsChange = DepositExceptionsView.Change - enum Change: Sendable, Hashable { - case added - case removed - } - } - } -} - -// MARK: - TransactionReview.View.DepositExceptionsView -extension TransactionReview.View { struct DepositExceptionsView: View { - var viewState: TransactionReview.DepositExceptionsState + var viewState: ViewState var body: some View { Card { @@ -48,7 +20,7 @@ extension TransactionReview.View { } struct AccountView: View { - let change: TransactionReview.DepositExceptionsChange + let change: Change var body: some View { InnerCard { @@ -99,6 +71,36 @@ extension TransactionReview.View { } } +extension InteractionReview.DepositExceptionsView { + struct ViewState: Sendable, Hashable { + var changes: IdentifiedArrayOf + } + + struct Change: Sendable, Identifiable, Hashable { + var id: AccountAddress.ID { account.address.id } + let account: Account + let resourcePreferenceChanges: IdentifiedArrayOf + let allowedDepositorChanges: IdentifiedArrayOf + + struct ResourcePreferenceChange: Sendable, Identifiable, Hashable { + var id: OnLedgerEntity.Resource.ID { resource.id } + let resource: OnLedgerEntity.Resource + let change: ResourcePreferenceUpdate + } + + struct AllowedDepositorChange: Sendable, Identifiable, Hashable { + var id: OnLedgerEntity.Resource.ID { resource.id } + let resource: OnLedgerEntity.Resource + let change: Change + + enum Change: Sendable, Hashable { + case added + case removed + } + } + } +} + extension ResourcePreferenceUpdate { var image: ImageAsset { switch self { @@ -123,7 +125,7 @@ extension ResourcePreferenceUpdate { } } -extension TransactionReview.DepositExceptionsChange.AllowedDepositorChange.Change { +extension InteractionReview.DepositExceptionsChange.AllowedDepositorChange.Change { var image: ImageAsset { switch self { case .added: diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewDepositSetting/TransactionReview+DepositSettingView.swift b/RadixWallet/Features/InteractionReview/Sections/DepositSetting/DepositSettingView.swift similarity index 71% rename from RadixWallet/Features/TransactionReviewFeature/TransactionReviewDepositSetting/TransactionReview+DepositSettingView.swift rename to RadixWallet/Features/InteractionReview/Sections/DepositSetting/DepositSettingView.swift index 9bf68a93fd..a002683aa4 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewDepositSetting/TransactionReview+DepositSettingView.swift +++ b/RadixWallet/Features/InteractionReview/Sections/DepositSetting/DepositSettingView.swift @@ -3,22 +3,13 @@ import SwiftUI typealias AccountDefaultDepositRule = DepositRule -extension TransactionReview { - struct DepositSettingState: Sendable, Hashable { - var changes: IdentifiedArrayOf - } - - struct DepositSettingChange: Sendable, Identifiable, Hashable { - var id: AccountAddress.ID { account.address.id } - let account: Account - let ruleChange: AccountDefaultDepositRule - } -} - // MARK: - TransactionReview.View.DepositSettingView -extension TransactionReview.View { +extension InteractionReview { + typealias DepositSettingState = DepositSettingView.ViewState + typealias DepositSettingChange = DepositSettingState.Change + struct DepositSettingView: View { - var viewState: TransactionReview.DepositSettingState + let viewState: ViewState var body: some View { Card { @@ -32,7 +23,7 @@ extension TransactionReview.View { } struct AccountView: View { - let change: TransactionReview.DepositSettingChange + let change: ViewState.Change var body: some SwiftUI.View { InnerCard { @@ -55,6 +46,19 @@ extension TransactionReview.View { } } +// MARK: - InteractionReview.DepositSettingView.ViewState +extension InteractionReview.DepositSettingView { + struct ViewState: Sendable, Hashable { + let changes: IdentifiedArrayOf + + struct Change: Sendable, Identifiable, Hashable { + var id: AccountAddress.ID { account.address.id } + let account: Account + let ruleChange: AccountDefaultDepositRule + } + } +} + extension AccountDefaultDepositRule { var string: String { switch self { diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+Data.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+Data.swift index 7561e20cf0..e65ba33697 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+Data.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+Data.swift @@ -13,8 +13,8 @@ extension InteractionReview { var unstakingFromValidators: InteractionReview.ValidatorsState? = nil var claimingFromValidators: InteractionReview.ValidatorsState? = nil - var accountDepositSetting: TransactionReview.DepositSettingState? = nil - var accountDepositExceptions: TransactionReview.DepositExceptionsState? = nil + var accountDepositSetting: InteractionReview.DepositSettingState? = nil + var accountDepositExceptions: InteractionReview.DepositExceptionsState? = nil var proofs: Proofs.State? = nil } diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+ExecutionSummary.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+ExecutionSummary.swift index ba3295b3be..a64182de5e 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+ExecutionSummary.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+ExecutionSummary.swift @@ -488,8 +488,8 @@ extension InteractionReview.Sections { func extractAccountDepositSetting( for validAccounts: [Account], defaultDepositRuleChanges: [AccountAddress: AccountDefaultDepositRule] - ) -> TransactionReview.DepositSettingState? { - let depositSettingChanges: [TransactionReview.DepositSettingChange] = validAccounts.compactMap { account in + ) -> Common.DepositSettingState? { + let depositSettingChanges: [Common.DepositSettingChange] = validAccounts.compactMap { account in guard let depositRuleChange = defaultDepositRuleChanges[account.address] else { return nil } return .init(account: account, ruleChange: depositRuleChange) } @@ -504,22 +504,22 @@ extension InteractionReview.Sections { resourcePreferenceChanges: [AccountAddress: [ResourceAddress: ResourcePreferenceUpdate]], authorizedDepositorsAdded: [AccountAddress: [ResourceOrNonFungible]], authorizedDepositorsRemoved: [AccountAddress: [ResourceOrNonFungible]] - ) async throws -> TransactionReview.DepositExceptionsState? { - let exceptionChanges: [TransactionReview.DepositExceptionsChange] = try await validAccounts.asyncCompactMap { account in + ) async throws -> Common.DepositExceptionsState? { + let exceptionChanges: [Common.DepositExceptionsChange] = try await validAccounts.asyncCompactMap { account in let resourcePreferenceChanges = try await resourcePreferenceChanges[account.address]? .asyncMap { resourcePreference in - try await TransactionReview.DepositExceptionsChange.ResourcePreferenceChange( + try await Common.DepositExceptionsChange.ResourcePreferenceChange( resource: onLedgerEntitiesClient.getResource(resourcePreference.key), change: resourcePreference.value ) } ?? [] let authorizedDepositorChanges = try await { - var changes: [TransactionReview.DepositExceptionsChange.AllowedDepositorChange] = [] + var changes: [Common.DepositExceptionsChange.AllowedDepositorChange] = [] if let authorizedDepositorsAdded = authorizedDepositorsAdded[account.address] { let added = try await authorizedDepositorsAdded.asyncMap { resourceOrNonFungible in let resourceAddress = resourceOrNonFungible.resourceAddress - return try await TransactionReview.DepositExceptionsChange.AllowedDepositorChange( + return try await Common.DepositExceptionsChange.AllowedDepositorChange( resource: onLedgerEntitiesClient.getResource(resourceAddress), change: .added ) @@ -529,7 +529,7 @@ extension InteractionReview.Sections { if let authorizedDepositorsRemoved = authorizedDepositorsRemoved[account.address] { let removed = try await authorizedDepositorsRemoved.asyncMap { resourceOrNonFungible in let resourceAddress = resourceOrNonFungible.resourceAddress - return try await TransactionReview.DepositExceptionsChange.AllowedDepositorChange( + return try await Common.DepositExceptionsChange.AllowedDepositorChange( resource: onLedgerEntitiesClient.getResource(resourceAddress), change: .removed ) @@ -542,7 +542,7 @@ extension InteractionReview.Sections { guard !resourcePreferenceChanges.isEmpty || !authorizedDepositorChanges.isEmpty else { return nil } - return TransactionReview.DepositExceptionsChange( + return Common.DepositExceptionsChange( account: account, resourcePreferenceChanges: IdentifiedArray(uncheckedUniqueElements: resourcePreferenceChanges), allowedDepositorChanges: IdentifiedArray(uncheckedUniqueElements: authorizedDepositorChanges) diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift index 633da3a3da..14c8fab427 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift @@ -12,7 +12,6 @@ extension InteractionReview.Sections { VStack(alignment: .leading, spacing: .medium1) { contributingToPools - redeemingFromPools // if let viewState = viewStore.stakingToValidators { @@ -38,13 +37,8 @@ extension InteractionReview.Sections { } } -// if let viewState = viewStore.depositSettingSection { -// accountDepositSettingSection(viewState) -// } -// -// if let viewState = viewStore.depositExceptionsSection { -// accountDepositExceptionsSection(viewState) -// } + accountDepositSetting + accountDepositExceptions } .animation(.easeInOut, value: store.contributingToPools?.isExpanded) .animation(.easeInOut, value: store.redeemingFromPools?.isExpanded) @@ -95,6 +89,26 @@ extension InteractionReview.Sections { } } + @ViewBuilder + private var accountDepositSetting: some SwiftUI.View { + if let viewState = store.accountDepositSetting { + VStack(alignment: .leading, spacing: .small2) { + Common.HeadingView.depositSetting + Common.DepositSettingView(viewState: viewState) + } + } + } + + @ViewBuilder + private var accountDepositExceptions: some SwiftUI.View { + if let viewState = store.accountDepositExceptions { + VStack(alignment: .leading, spacing: .small2) { + Common.HeadingView.depositExceptions + Common.DepositExceptionsView(viewState: viewState) + } + } + } + @ViewBuilder private var dAppsUsed: some SwiftUI.View { if let childStore = store.scope(state: \.dAppsUsed, action: \.child.dAppsUsed) { diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections.swift b/RadixWallet/Features/InteractionReview/Sections/Sections.swift index 4706182d16..949de78788 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections.swift @@ -17,8 +17,8 @@ extension InteractionReview { var unstakingFromValidators: InteractionReview.ValidatorsState? = nil var claimingFromValidators: InteractionReview.ValidatorsState? = nil - var accountDepositSetting: TransactionReview.DepositSettingState? = nil - var accountDepositExceptions: TransactionReview.DepositExceptionsState? = nil + var accountDepositSetting: InteractionReview.DepositSettingState? = nil + var accountDepositExceptions: InteractionReview.DepositExceptionsState? = nil // The proofs are set here (within the resolve logic) but should be rendered and handled by the parent view, since they may be placed outside the Sections. var proofs: Proofs.State? = nil diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index acb45ebaf0..f5a42e85be 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -70,8 +70,8 @@ extension TransactionReview { let stakingToValidators: Common.ValidatorsState? let unstakingFromValidators: Common.ValidatorsState? let claimingFromValidators: Common.ValidatorsState? - let depositSettingSection: DepositSettingState? - let depositExceptionsSection: DepositExceptionsState? + let depositSettingSection: Common.DepositSettingState? + let depositExceptionsSection: Common.DepositExceptionsState? var approvalSliderControlState: ControlState { // TODO: Is this the logic we want? @@ -310,18 +310,18 @@ extension TransactionReview { } @ViewBuilder - private func accountDepositSettingSection(_ viewState: DepositSettingState) -> some SwiftUI.View { + private func accountDepositSettingSection(_ viewState: Common.DepositSettingState) -> some SwiftUI.View { VStack(alignment: .leading, spacing: .small2) { Common.HeadingView.depositSetting - DepositSettingView(viewState: viewState) + Common.DepositSettingView(viewState: viewState) } } @ViewBuilder - private func accountDepositExceptionsSection(_ viewState: DepositExceptionsState) -> some SwiftUI.View { + private func accountDepositExceptionsSection(_ viewState: Common.DepositExceptionsState) -> some SwiftUI.View { VStack(alignment: .leading, spacing: .small2) { Common.HeadingView.depositExceptions - DepositExceptionsView(viewState: viewState) + Common.DepositExceptionsView(viewState: viewState) } } diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift index 6b06727fa5..73df705b01 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift @@ -32,8 +32,8 @@ struct TransactionReview: Sendable, FeatureReducer { var unstakingFromValidators: Common.ValidatorsState? = nil var claimingFromValidators: Common.ValidatorsState? = nil - var accountDepositSetting: DepositSettingState? = nil - var accountDepositExceptions: DepositExceptionsState? = nil + var accountDepositSetting: Common.DepositSettingState? = nil + var accountDepositExceptions: Common.DepositExceptionsState? = nil var proofs: Common.Proofs.State? = nil var networkFee: TransactionReviewNetworkFee.State? = nil From 76b65f4dd26676166032edd06c23fa24fa9f4275 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 22 Oct 2024 13:06:32 -0300 Subject: [PATCH 23/63] implement for validators in Section as well --- .../Sections/Sections+View.swift | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift index 14c8fab427..473a0bc67d 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift @@ -14,17 +14,9 @@ extension InteractionReview.Sections { contributingToPools redeemingFromPools -// if let viewState = viewStore.stakingToValidators { -// stakingToValidatorsSection(viewState) -// } -// -// if let viewState = viewStore.unstakingFromValidators { -// unstakingFromValidatorsSection(viewState) -// } -// -// if let viewState = viewStore.claimingFromValidators { -// claimingFromValidatorsSection(viewState) -// } + stakingToValidators + unstakingFromValidators + claimingFromValidators dAppsUsed @@ -42,6 +34,9 @@ extension InteractionReview.Sections { } .animation(.easeInOut, value: store.contributingToPools?.isExpanded) .animation(.easeInOut, value: store.redeemingFromPools?.isExpanded) + .animation(.easeInOut, value: store.stakingToValidators?.isExpanded) + .animation(.easeInOut, value: store.unstakingFromValidators?.isExpanded) + .animation(.easeInOut, value: store.claimingFromValidators?.isExpanded) .animation(.easeInOut, value: store.dAppsUsed?.isExpanded) } .destinations(with: store) @@ -89,6 +84,33 @@ extension InteractionReview.Sections { } } + @ViewBuilder + private var stakingToValidators: some SwiftUI.View { + if let viewState = store.stakingToValidators { + Common.ValidatorsView(heading: .stakingToValidators, viewState: viewState) { +// store.send(.view(.expandStakingToValidatorsTapped)) + } + } + } + + @ViewBuilder + private var unstakingFromValidators: some SwiftUI.View { + if let viewState = store.unstakingFromValidators { + Common.ValidatorsView(heading: .unstakingFromValidators, viewState: viewState) { +// store.send(.view(.expandUnstakingFromValidatorsTapped)) + } + } + } + + @ViewBuilder + private var claimingFromValidators: some SwiftUI.View { + if let viewState = store.claimingFromValidators { + Common.ValidatorsView(heading: .claimingFromValidators, viewState: viewState) { +// store.send(.view(.expandClaimingFromValidatorsTapped)) + } + } + } + @ViewBuilder private var accountDepositSetting: some SwiftUI.View { if let viewState = store.accountDepositSetting { From 650637e4023fbc7897fd96f897d9f8fbb12d8efd Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 22 Oct 2024 13:30:01 -0300 Subject: [PATCH 24/63] clean up TransactionReview --- .../Sections/Sections+View.swift | 12 +- .../InteractionReview/Sections/Sections.swift | 77 ++++-- .../PreAuthorizationReview.swift | 8 +- .../TransactionReview+View.swift | 205 +--------------- .../TransactionReview.swift | 220 +----------------- 5 files changed, 78 insertions(+), 444 deletions(-) diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift index 473a0bc67d..f4b340aeeb 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift @@ -58,7 +58,7 @@ extension InteractionReview.Sections { VStack(alignment: .leading, spacing: .small2) { let isExpanded = childStore.isExpanded Common.ExpandableHeadingView(heading: .contributingToPools, isExpanded: isExpanded) { -// store.send(.view(.expandContributingToPoolsTapped)) + store.send(.view(.expandableItemToggled(.contributingToPools))) } if isExpanded { InteractionReviewPools.View(store: childStore) @@ -74,7 +74,7 @@ extension InteractionReview.Sections { VStack(alignment: .leading, spacing: .small2) { let isExpanded = childStore.isExpanded Common.ExpandableHeadingView(heading: .redeemingFromPools, isExpanded: isExpanded) { -// store.send(.view(.expandRedeemingFromPoolsTapped)) + store.send(.view(.expandableItemToggled(.redeemingFromPools))) } if isExpanded { InteractionReviewPools.View(store: childStore) @@ -88,7 +88,7 @@ extension InteractionReview.Sections { private var stakingToValidators: some SwiftUI.View { if let viewState = store.stakingToValidators { Common.ValidatorsView(heading: .stakingToValidators, viewState: viewState) { -// store.send(.view(.expandStakingToValidatorsTapped)) + store.send(.view(.expandableItemToggled(.stakingToValidators))) } } } @@ -97,7 +97,7 @@ extension InteractionReview.Sections { private var unstakingFromValidators: some SwiftUI.View { if let viewState = store.unstakingFromValidators { Common.ValidatorsView(heading: .unstakingFromValidators, viewState: viewState) { -// store.send(.view(.expandUnstakingFromValidatorsTapped)) + store.send(.view(.expandableItemToggled(.unstakingFromValidators))) } } } @@ -106,7 +106,7 @@ extension InteractionReview.Sections { private var claimingFromValidators: some SwiftUI.View { if let viewState = store.claimingFromValidators { Common.ValidatorsView(heading: .claimingFromValidators, viewState: viewState) { -// store.send(.view(.expandClaimingFromValidatorsTapped)) + store.send(.view(.expandableItemToggled(.claimingFromValidators))) } } } @@ -137,7 +137,7 @@ extension InteractionReview.Sections { VStack(alignment: .leading, spacing: .small2) { let isExpanded = childStore.isExpanded Common.ExpandableHeadingView(heading: .usingDapps, isExpanded: isExpanded) { -// store.send(.view(.expandDappsUsedTapped)) + store.send(.view(.expandableItemToggled(.dAppsUsed))) } if isExpanded { InteractionReviewDappsUsed.View(store: childStore) diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections.swift b/RadixWallet/Features/InteractionReview/Sections/Sections.swift index 949de78788..6d2efcdb86 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections.swift @@ -31,12 +31,22 @@ extension InteractionReview { enum ViewAction: Sendable, Equatable { case appeared + case expandableItemToggled(ExpandableItem) + + enum ExpandableItem: Sendable, Equatable { + case dAppsUsed, contributingToPools, redeemingFromPools, stakingToValidators, unstakingFromValidators, claimingFromValidators + } } enum InternalAction: Sendable, Equatable { - case resolveExecutionSummary(ExecutionSummary, NetworkID) - case simulate + case parent(ParentAction) case setSections(Common.SectionsData?) + + enum ParentAction: Sendable, Equatable { + case resolveExecutionSummary(ExecutionSummary, NetworkID) + case simulate + case showResourceDetails(OnLedgerEntity.Resource, ResourceBalance.Details) + } } @CasePathable @@ -133,29 +143,31 @@ extension InteractionReview { func reduce(into state: inout State, viewAction: ViewAction) -> Effect { switch viewAction { case .appeared: - .none + return .none + + case let .expandableItemToggled(item): + switch item { + case .dAppsUsed: + state.dAppsUsed?.isExpanded.toggle() + case .contributingToPools: + state.contributingToPools?.isExpanded.toggle() + case .redeemingFromPools: + state.redeemingFromPools?.isExpanded.toggle() + case .stakingToValidators: + state.stakingToValidators?.isExpanded.toggle() + case .unstakingFromValidators: + state.unstakingFromValidators?.isExpanded.toggle() + case .claimingFromValidators: + state.claimingFromValidators?.isExpanded.toggle() + } + return .none } } func reduce(into state: inout State, internalAction: InternalAction) -> Effect { switch internalAction { - case let .resolveExecutionSummary(executionSummary, networkID): - return .run { send in - let sections = try await sections(for: executionSummary, networkID: networkID) - await send(.internal(.setSections(sections))) - } catch: { error, send in - loggerGlobal.error("Failed to extract sections from ExecutionSummary, error: \(error)") - await send(.internal(.setSections(nil))) - } - - case .simulate: - return .run { send in - let sections = try await simulateSections() - await send(.internal(.setSections(sections))) - } catch: { error, send in - loggerGlobal.error("Failed to extract sections, error: \(error)") - await send(.internal(.setSections(nil))) - } + case let .parent(action): + return reduce(into: &state, parentAction: action) case let .setSections(sections): guard let sections else { @@ -177,6 +189,31 @@ extension InteractionReview { } } + func reduce(into state: inout State, parentAction: InternalAction.ParentAction) -> Effect { + switch parentAction { + case let .resolveExecutionSummary(executionSummary, networkID): + .run { send in + let sections = try await sections(for: executionSummary, networkID: networkID) + await send(.internal(.setSections(sections))) + } catch: { error, send in + loggerGlobal.error("Failed to extract sections from ExecutionSummary, error: \(error)") + await send(.internal(.setSections(nil))) + } + + case .simulate: + .run { send in + let sections = try await simulateSections() + await send(.internal(.setSections(sections))) + } catch: { error, send in + loggerGlobal.error("Failed to extract sections, error: \(error)") + await send(.internal(.setSections(nil))) + } + + case let .showResourceDetails(resource, details): + resourceDetailsEffect(state: &state, resource: resource, details: details) + } + } + func reduce(into state: inout State, childAction: ChildAction) -> Effect { switch childAction { case let .withdrawals(.delegate(.showAsset(transfer, token))), diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 6437dedb0e..396fb8487e 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -93,6 +93,12 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { case let .sections(.internal(.setSections(sections))): state.proofs = sections?.proofs return .none + + case let .proofs(.delegate(.showAsset(proof))): + let resource = proof.resourceBalance.resource + let details = proof.resourceBalance.details + return .send(.child(.sections(.internal(.parent(.showResourceDetails(resource, details)))))) + default: return .none } @@ -101,7 +107,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { private extension PreAuthorizationReview { func getSections() -> Effect { - .send(.child(.sections(.internal(.simulate)))) + .send(.child(.sections(.internal(.parent(.simulate))))) } func startTimer(expirationDate: Date) -> Effect { diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index f5a42e85be..c8fbff7865 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -17,10 +17,6 @@ extension TransactionReview.State { var viewState: TransactionReview.ViewState { .init( message: message.plaintext, - isExpandedDappUsed: dAppsUsed?.isExpanded == true, - isExpandedContributingToPools: contributingToPools?.isExpanded == true, - isExpandedRedeemingFromPools: redeemingFromPools?.isExpanded == true, - showTransferLine: withdrawals != nil && deposits != nil, viewControlState: viewControlState, rawTransaction: displayMode.rawTransaction, showApprovalSlider: reviewedTransaction != nil, @@ -28,12 +24,7 @@ extension TransactionReview.State { sliderResetDate: sliderResetDate, canToggleViewMode: reviewedTransaction != nil && reviewedTransaction?.isNonConforming == false, viewRawTransactionButtonState: reviewedTransaction?.feePayer.isSuccess == true ? .enabled : .disabled, - proposingDappMetadata: proposingDappMetadata, - stakingToValidators: stakingToValidators, - unstakingFromValidators: unstakingFromValidators, - claimingFromValidators: claimingFromValidators, - depositSettingSection: accountDepositSetting, - depositExceptionsSection: accountDepositExceptions + proposingDappMetadata: proposingDappMetadata ) } @@ -50,14 +41,7 @@ extension TransactionReview.State { extension TransactionReview { struct ViewState: Equatable { let message: String? - let isExpandedDappUsed: Bool - let isExpandedContributingToPools: Bool - let isExpandedRedeemingFromPools: Bool - var isExpandedStakingToValidators: Bool { stakingToValidators?.isExpanded == true } - var isExpandedUnstakingFromValidators: Bool { unstakingFromValidators?.isExpanded == true } - var isExpandedClaimingFromValidators: Bool { claimingFromValidators?.isExpanded == true } - - let showTransferLine: Bool + let viewControlState: ControlState let rawTransaction: String? let showApprovalSlider: Bool @@ -67,12 +51,6 @@ extension TransactionReview { let viewRawTransactionButtonState: ControlState let proposingDappMetadata: DappMetadata.Ledger? - let stakingToValidators: Common.ValidatorsState? - let unstakingFromValidators: Common.ValidatorsState? - let claimingFromValidators: Common.ValidatorsState? - let depositSettingSection: Common.DepositSettingState? - let depositExceptionsSection: Common.DepositExceptionsState? - var approvalSliderControlState: ControlState { // TODO: Is this the logic we want? canApproveTX ? viewControlState : .disabled @@ -100,12 +78,6 @@ extension TransactionReview { coreView(with: viewStore) .controlState(viewStore.viewControlState) .background(.white) - .animation(.easeInOut, value: viewStore.isExpandedDappUsed) - .animation(.easeInOut, value: viewStore.isExpandedContributingToPools) - .animation(.easeInOut, value: viewStore.isExpandedRedeemingFromPools) - .animation(.easeInOut, value: viewStore.isExpandedStakingToValidators) - .animation(.easeInOut, value: viewStore.isExpandedUnstakingFromValidators) - .animation(.easeInOut, value: viewStore.isExpandedClaimingFromValidators) .toolbar { ToolbarItem(placement: .automatic) { if viewStore.canToggleViewMode { @@ -231,100 +203,6 @@ extension TransactionReview { return Common.Sections.View(store: childStore) } - private var withdrawalsSection: some SwiftUI.View { - IfLetStore(store.scope(state: \.withdrawals) { .child(.withdrawals($0)) }) { childStore in - VStack(alignment: .leading, spacing: .small2) { - Common.HeadingView.withdrawing - Common.Accounts.View(store: childStore) - } - } - } - - private func usingDappsSection(isExpanded: Bool) -> some SwiftUI.View { - IfLetStore(store.scope(state: \.dAppsUsed) { .child(.dAppsUsed($0)) }) { childStore in - VStack(alignment: .leading, spacing: .small2) { - Common.ExpandableHeadingView(heading: .usingDapps, isExpanded: isExpanded) { - store.send(.view(.expandUsingDappsTapped)) - } - if isExpanded { - InteractionReviewDappsUsed.View(store: childStore) - .transition(.opacity.combined(with: .scale(scale: 0.95))) - } - } - } - } - - private func contributingToPools(isExpanded: Bool) -> some SwiftUI.View { - IfLetStore(store.scope(state: \.contributingToPools) { .child(.contributingToPools($0)) }) { childStore in - VStack(alignment: .leading, spacing: .small2) { - Common.ExpandableHeadingView(heading: .contributingToPools, isExpanded: isExpanded) { - store.send(.view(.expandContributingToPoolsTapped)) - } - if isExpanded { - InteractionReviewPools.View(store: childStore) - .transition(.opacity.combined(with: .scale(scale: 0.95))) - } - } - } - } - - private func redeemingFromPools(isExpanded: Bool) -> some SwiftUI.View { - IfLetStore(store.scope(state: \.redeemingFromPools) { .child(.redeemingFromPools($0)) }) { childStore in - VStack(alignment: .leading, spacing: .small2) { - Common.ExpandableHeadingView(heading: .redeemingFromPools, isExpanded: isExpanded) { - store.send(.view(.expandRedeemingFromPoolsTapped)) - } - if isExpanded { - InteractionReviewPools.View(store: childStore) - .transition(.opacity.combined(with: .scale(scale: 0.95))) - } - } - } - } - - private func stakingToValidatorsSection(_ viewState: InteractionReview.ValidatorsView.ViewState) -> some SwiftUI.View { - Common.ValidatorsView(heading: .stakingToValidators, viewState: viewState) { - store.send(.view(.expandStakingToValidatorsTapped)) - } - } - - private func unstakingFromValidatorsSection(_ viewState: InteractionReview.ValidatorsView.ViewState) -> some SwiftUI.View { - Common.ValidatorsView(heading: .unstakingFromValidators, viewState: viewState) { - store.send(.view(.expandUnstakingFromValidatorsTapped)) - } - } - - private func claimingFromValidatorsSection(_ viewState: InteractionReview.ValidatorsView.ViewState) -> some SwiftUI.View { - Common.ValidatorsView(heading: .claimingFromValidators, viewState: viewState) { - store.send(.view(.expandClaimingFromValidatorsTapped)) - } - } - - private var depositsSection: some SwiftUI.View { - IfLetStore(store.scope(state: \.deposits) { .child(.deposits($0)) }) { childStore in - VStack(alignment: .leading, spacing: .small2) { - Common.HeadingView.depositing - Common.Accounts.View(store: childStore) - } - } - } - - @ViewBuilder - private func accountDepositSettingSection(_ viewState: Common.DepositSettingState) -> some SwiftUI.View { - VStack(alignment: .leading, spacing: .small2) { - Common.HeadingView.depositSetting - Common.DepositSettingView(viewState: viewState) - } - } - - @ViewBuilder - private func accountDepositExceptionsSection(_ viewState: Common.DepositExceptionsState) -> some SwiftUI.View { - VStack(alignment: .leading, spacing: .small2) { - Common.HeadingView.depositExceptions - Common.DepositExceptionsView(viewState: viewState) - } - } - private var proofsSection: some SwiftUI.View { let proofsStore = store.scope(state: \.proofs) { .child(.proofs($0)) } return IfLetStore(proofsStore) { childStore in @@ -355,24 +233,9 @@ private extension View { func destinations(with store: StoreOf) -> some View { let destinationStore = store.destination return customizeGuarantees(with: destinationStore) - .dApp(with: destinationStore) - .fungibleTokenDetails(with: destinationStore) - .nonFungibleTokenDetails(with: destinationStore) - .lsuDetails(with: destinationStore) - .poolUnitDetails(with: destinationStore) .customizeFees(with: destinationStore) .signing(with: destinationStore) .submitting(with: destinationStore) - .unknownComponents(with: destinationStore) - .rawTransactionAlert(with: destinationStore) - } - - private func rawTransactionAlert(with destinationStore: PresentationStoreOf) -> some View { - alert( - store: destinationStore, - state: /TransactionReview.Destination.State.rawTransactionAlert, - action: TransactionReview.Destination.Action.rawTransactionAlert - ) } private func customizeGuarantees(with destinationStore: PresentationStoreOf) -> some View { @@ -384,70 +247,6 @@ private extension View { ) } - private func dApp(with destinationStore: PresentationStoreOf) -> some View { - sheet( - store: destinationStore, - state: /TransactionReview.Destination.State.dApp, - action: TransactionReview.Destination.Action.dApp, - content: { detailsStore in - WithNavigationBar { - destinationStore.send(.dismiss) - } content: { - DappDetails.View(store: detailsStore) - } - } - ) - } - - private func unknownComponents(with destinationStore: PresentationStoreOf) -> some View { - sheet( - store: destinationStore, - state: /TransactionReview.Destination.State.unknownDappComponents, - action: TransactionReview.Destination.Action.unknownDappComponents, - content: { - InteractionReview.UnknownDappComponents.View(store: $0) - .inNavigationStack - .presentationDetents([.medium]) - } - ) - } - - private func fungibleTokenDetails(with destinationStore: PresentationStoreOf) -> some View { - sheet( - store: destinationStore, - state: /TransactionReview.Destination.State.fungibleTokenDetails, - action: TransactionReview.Destination.Action.fungibleTokenDetails, - content: { FungibleTokenDetails.View(store: $0) } - ) - } - - private func nonFungibleTokenDetails(with destinationStore: PresentationStoreOf) -> some View { - sheet( - store: destinationStore, - state: /TransactionReview.Destination.State.nonFungibleTokenDetails, - action: TransactionReview.Destination.Action.nonFungibleTokenDetails, - content: { NonFungibleTokenDetails.View(store: $0) } - ) - } - - private func lsuDetails(with destinationStore: PresentationStoreOf) -> some View { - sheet( - store: destinationStore, - state: /TransactionReview.Destination.State.lsuDetails, - action: TransactionReview.Destination.Action.lsuDetails, - content: { LSUDetails.View(store: $0) } - ) - } - - private func poolUnitDetails(with destinationStore: PresentationStoreOf) -> some View { - sheet( - store: destinationStore, - state: /TransactionReview.Destination.State.poolUnitDetails, - action: TransactionReview.Destination.Action.poolUnitDetails, - content: { PoolUnitDetails.View(store: $0) } - ) - } - private func customizeFees(with destinationStore: PresentationStoreOf) -> some View { sheet( store: destinationStore, diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift index 73df705b01..2ceefc23fa 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift @@ -22,18 +22,6 @@ struct TransactionReview: Sendable, FeatureReducer { var reviewedTransaction: ReviewedTransaction? = nil var sections: Common.Sections.State = .init() - var withdrawals: Common.Accounts.State? = nil - var dAppsUsed: InteractionReviewDappsUsed.State? = nil - var contributingToPools: InteractionReviewPools.State? = nil - var redeemingFromPools: InteractionReviewPools.State? = nil - var deposits: Common.Accounts.State? = nil - - var stakingToValidators: Common.ValidatorsState? = nil - var unstakingFromValidators: Common.ValidatorsState? = nil - var claimingFromValidators: Common.ValidatorsState? = nil - - var accountDepositSetting: Common.DepositSettingState? = nil - var accountDepositExceptions: Common.DepositExceptionsState? = nil var proofs: Common.Proofs.State? = nil var networkFee: TransactionReviewNetworkFee.State? = nil @@ -101,30 +89,18 @@ struct TransactionReview: Sendable, FeatureReducer { case appeared case showRawTransactionTapped case copyRawTransactionTapped - case expandContributingToPoolsTapped - case expandRedeemingFromPoolsTapped - case expandStakingToValidatorsTapped - case expandUnstakingFromValidatorsTapped - case expandClaimingFromValidatorsTapped - case expandUsingDappsTapped case approvalSliderSlid } @CasePathable enum ChildAction: Sendable, Equatable { case sections(Common.Sections.Action) - case withdrawals(Common.Accounts.Action) - case deposits(Common.Accounts.Action) - case dAppsUsed(InteractionReviewDappsUsed.Action) - case contributingToPools(InteractionReviewPools.Action) - case redeemingFromPools(InteractionReviewPools.Action) case proofs(Common.Proofs.Action) case networkFee(TransactionReviewNetworkFee.Action) } enum InternalAction: Sendable, Equatable { case previewLoaded(TaskResult) - case updateSections(Common.SectionsData?) case buildTransactionIntentResult(TaskResult) case notarizeResult(TaskResult) case determineFeePayerResult(TaskResult) @@ -142,32 +118,14 @@ struct TransactionReview: Sendable, FeatureReducer { case customizeGuarantees(TransactionReviewGuarantees.State) case signing(Signing.State) case submitting(SubmitTransaction.State) - case dApp(DappDetails.State) case customizeFees(CustomizeFees.State) - case fungibleTokenDetails(FungibleTokenDetails.State) - case nonFungibleTokenDetails(NonFungibleTokenDetails.State) - case poolUnitDetails(PoolUnitDetails.State) - case lsuDetails(LSUDetails.State) - case unknownDappComponents(Common.UnknownDappComponents.State) - case rawTransactionAlert(AlertState) } enum Action: Sendable, Equatable { case customizeGuarantees(TransactionReviewGuarantees.Action) case signing(Signing.Action) case submitting(SubmitTransaction.Action) - case dApp(DappDetails.Action) case customizeFees(CustomizeFees.Action) - case fungibleTokenDetails(FungibleTokenDetails.Action) - case nonFungibleTokenDetails(NonFungibleTokenDetails.Action) - case lsuDetails(LSUDetails.Action) - case poolUnitDetails(PoolUnitDetails.Action) - case unknownDappComponents(Common.UnknownDappComponents.Action) - case rawTransactionAlert(RawTransactionAlert) - - enum RawTransactionAlert: Sendable, Equatable { - case continueTapped - } } var body: some ReducerOf { @@ -183,24 +141,6 @@ struct TransactionReview: Sendable, FeatureReducer { Scope(state: /State.submitting, action: /Action.submitting) { SubmitTransaction() } - Scope(state: /State.dApp, action: /Action.dApp) { - DappDetails() - } - Scope(state: /State.fungibleTokenDetails, action: /Action.fungibleTokenDetails) { - FungibleTokenDetails() - } - Scope(state: /State.nonFungibleTokenDetails, action: /Action.nonFungibleTokenDetails) { - NonFungibleTokenDetails() - } - Scope(state: /State.poolUnitDetails, action: /Action.poolUnitDetails) { - PoolUnitDetails() - } - Scope(state: /State.lsuDetails, action: /Action.lsuDetails) { - LSUDetails() - } - Scope(state: /State.unknownDappComponents, action: /Action.unknownDappComponents) { - Common.UnknownDappComponents() - } } } @@ -223,21 +163,6 @@ struct TransactionReview: Sendable, FeatureReducer { .ifLet(\.networkFee, action: /Action.child .. ChildAction.networkFee) { TransactionReviewNetworkFee() } - .ifLet(\.deposits, action: /Action.child .. ChildAction.deposits) { - Common.Accounts() - } - .ifLet(\.dAppsUsed, action: /Action.child .. ChildAction.dAppsUsed) { - InteractionReviewDappsUsed() - } - .ifLet(\.contributingToPools, action: /Action.child .. ChildAction.contributingToPools) { - InteractionReviewPools() - } - .ifLet(\.redeemingFromPools, action: /Action.child .. ChildAction.redeemingFromPools) { - InteractionReviewPools() - } - .ifLet(\.withdrawals, action: /Action.child .. ChildAction.withdrawals) { - Common.Accounts() - } .ifLet(\.proofs, action: /Action.child .. ChildAction.proofs) { Common.Proofs() } @@ -282,30 +207,6 @@ struct TransactionReview: Sendable, FeatureReducer { pasteboardClient.copyString(manifest) return .none - case .expandContributingToPoolsTapped: - state.contributingToPools?.isExpanded.toggle() - return .none - - case .expandRedeemingFromPoolsTapped: - state.redeemingFromPools?.isExpanded.toggle() - return .none - - case .expandStakingToValidatorsTapped: - state.stakingToValidators?.isExpanded.toggle() - return .none - - case .expandUnstakingFromValidatorsTapped: - state.unstakingFromValidators?.isExpanded.toggle() - return .none - - case .expandClaimingFromValidatorsTapped: - state.claimingFromValidators?.isExpanded.toggle() - return .none - - case .expandUsingDappsTapped: - state.dAppsUsed?.isExpanded.toggle() - return .none - case .approvalSliderSlid: state.canApproveTX = false state.printFeePayerInfo() @@ -364,33 +265,10 @@ struct TransactionReview: Sendable, FeatureReducer { return .none } - case let .withdrawals(.delegate(.showAsset(transfer, token))), - let .deposits(.delegate(.showAsset(transfer, token))): - return resourceDetailsEffect(state: &state, resource: transfer.resource, details: transfer.details, nft: token) - - case let .dAppsUsed(.delegate(.openDapp(dAppID))), let .contributingToPools(.delegate(.openDapp(dAppID))), let .redeemingFromPools(.delegate(.openDapp(dAppID))): - state.destination = .dApp(.init(dAppDefinitionAddress: dAppID)) - return .none - - case let .dAppsUsed(.delegate(.openUnknownAddresses(components))): - state.destination = .unknownDappComponents(.init( - title: L10n.TransactionReview.unknownComponents(components.count), - rowHeading: L10n.Common.component, - addresses: components.map { .component($0) } - )) - return .none - - case let .contributingToPools(.delegate(.openUnknownAddresses(pools))), let .redeemingFromPools(.delegate(.openUnknownAddresses(pools))): - state.destination = .unknownDappComponents(.init( - title: L10n.TransactionReview.unknownPools(pools.count), - rowHeading: L10n.Common.pool, - addresses: pools.map { .resourcePool($0) } - )) - return .none - case let .proofs(.delegate(.showAsset(proof))): let resource = proof.resourceBalance.resource - return resourceDetailsEffect(state: &state, resource: resource, details: proof.resourceBalance.details) + let details = proof.resourceBalance.details + return .send(.child(.sections(.internal(.parent(.showResourceDetails(resource, details)))))) case .networkFee(.delegate(.showCustomizeFees)): guard let reviewedTransaction = state.reviewedTransaction else { @@ -434,26 +312,6 @@ struct TransactionReview: Sendable, FeatureReducer { return review(&state, executionSummary: preview.analyzedManifestToReview) .concatenate(with: determineFeePayer(state, reviewedTransaction: reviewedTransaction)) - case let .updateSections(sections): - guard let sections else { - state.destination = .rawTransactionAlert(.rawTransaction) - return showRawTransaction(&state) - } - - state.withdrawals = sections.withdrawals - state.dAppsUsed = sections.dAppsUsed - state.contributingToPools = sections.contributingToPools - state.redeemingFromPools = sections.redeemingFromPools - state.stakingToValidators = sections.stakingToValidators - state.unstakingFromValidators = sections.unstakingFromValidators - state.claimingFromValidators = sections.claimingFromValidators - state.deposits = sections.deposits - state.accountDepositSetting = sections.accountDepositSetting - state.accountDepositExceptions = sections.accountDepositExceptions - state.proofs = sections.proofs - - return .none - case let .buildTransactionIntentResult(.success(intent)): guard let reviewedTransaction = state.reviewedTransaction else { return .none @@ -595,20 +453,6 @@ struct TransactionReview: Sendable, FeatureReducer { } } -extension AlertState { - static var rawTransaction: AlertState { - AlertState { - TextState(L10n.TransactionReview.NonConformingManifestWarning.title) - } actions: { - ButtonState(action: .continueTapped) { - TextState(L10n.Common.continue) - } - } message: { - TextState(L10n.TransactionReview.NonConformingManifestWarning.message) - } - } -} - extension Collection { var customizableGuarantees: [TransactionReviewGuarantee.State] { flatMap { account in @@ -636,7 +480,7 @@ extension TransactionReview { state.networkFee = .init(reviewedTransaction: reviewedTransaction) - return .send(.child(.sections(.internal(.resolveExecutionSummary(executionSummary, networkID))))) + return .send(.child(.sections(.internal(.parent(.resolveExecutionSummary(executionSummary, networkID)))))) } func showRawTransaction(_ state: inout State) -> Effect { @@ -686,58 +530,6 @@ extension TransactionReview { } } } - - func resourceDetailsEffect( - state: inout State, - resource: OnLedgerEntity.Resource, - details: ResourceBalance.Details, - nft: OnLedgerEntity.NonFungibleToken? = nil - ) -> Effect { - switch details { - case let .fungible(details): - state.destination = .fungibleTokenDetails(.init( - resourceAddress: resource.resourceAddress, - resource: .success(resource), - ownedFungibleResource: .init( - resourceAddress: resource.resourceAddress, - atLedgerState: resource.atLedgerState, - amount: details.amount, - metadata: resource.metadata - ), - isXRD: details.isXRD - )) - - case let .nonFungible(details): - state.destination = .nonFungibleTokenDetails(.init( - resourceAddress: resource.resourceAddress, - resourceDetails: .success(resource), - token: details, - ledgerState: resource.atLedgerState - )) - - case let .liquidStakeUnit(details): - state.destination = .lsuDetails(.init( - validator: details.validator, - stakeUnitResource: .init(resource: details.resource, amount: .init(nominalAmount: details.amount)), - xrdRedemptionValue: details.worth - )) - - case let .poolUnit(details): - state.destination = .poolUnitDetails(.init(resourcesDetails: details.details)) - - case let .stakeClaimNFT(details): - state.destination = .nonFungibleTokenDetails(.init( - resourceAddress: resource.resourceAddress, - resourceDetails: .success(resource), - token: nft, - ledgerState: resource.atLedgerState, - stakeClaim: details.stakeClaimTokens.stakeClaims.first, - isClaimStakeEnabled: false - )) - } - - return .none - } } // MARK: - FailedToAddLockFee @@ -835,7 +627,7 @@ extension ResourceBalance { extension TransactionReview.State { var allGuarantees: [TransactionGuarantee] { - deposits?.accounts.flatMap { $0.transfers.compactMap(\.fungibleGuarantee) } ?? [] + sections.deposits?.accounts.flatMap { $0.transfers.compactMap(\.fungibleGuarantee) } ?? [] } mutating func applyGuarantee( @@ -843,11 +635,11 @@ extension TransactionReview.State { transferID: InteractionReview.Transfer.ID ) { guard let accountID = accountID(for: transferID) else { return } - deposits?.accounts[id: accountID]?.transfers[id: transferID]?.fungibleGuarantee = updated + sections.deposits?.accounts[id: accountID]?.transfers[id: transferID]?.fungibleGuarantee = updated } private func accountID(for transferID: InteractionReview.Transfer.ID) -> AccountAddress? { - for account in deposits?.accounts ?? [] { + for account in sections.deposits?.accounts ?? [] { for transfer in account.transfers { if transfer.id == transferID { return account.id From c67c60fb03b8334a5dbbe5735b019e17f4ddd515 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 22 Oct 2024 13:59:52 -0300 Subject: [PATCH 25/63] FungibleTokenDetails use ObservableState --- .../FungibleTokenDetails+Reducer.swift | 4 + .../Details/FungibleTokenDetails+View.swift | 75 ++++++++----------- .../UnknownDappComponents+View.swift | 20 ++--- 3 files changed, 46 insertions(+), 53 deletions(-) diff --git a/RadixWallet/Features/AssetsFeature/Components/FungibleAssetList/Components/Details/FungibleTokenDetails+Reducer.swift b/RadixWallet/Features/AssetsFeature/Components/FungibleAssetList/Components/Details/FungibleTokenDetails+Reducer.swift index bb92d22b29..0cd3f8402f 100644 --- a/RadixWallet/Features/AssetsFeature/Components/FungibleAssetList/Components/Details/FungibleTokenDetails+Reducer.swift +++ b/RadixWallet/Features/AssetsFeature/Components/FungibleAssetList/Components/Details/FungibleTokenDetails+Reducer.swift @@ -2,7 +2,9 @@ import ComposableArchitecture import SwiftUI // MARK: - FungibleTokenDetails +@Reducer struct FungibleTokenDetails: Sendable, FeatureReducer { + @ObservableState struct State: Sendable, Hashable { let resourceAddress: ResourceAddress var resource: Loadable @@ -27,6 +29,8 @@ struct FungibleTokenDetails: Sendable, FeatureReducer { } } + typealias Action = FeatureAction + enum ViewAction: Sendable, Equatable { case closeButtonTapped case task diff --git a/RadixWallet/Features/AssetsFeature/Components/FungibleAssetList/Components/Details/FungibleTokenDetails+View.swift b/RadixWallet/Features/AssetsFeature/Components/FungibleAssetList/Components/Details/FungibleTokenDetails+View.swift index 45ee72644b..0f315cd235 100644 --- a/RadixWallet/Features/AssetsFeature/Components/FungibleAssetList/Components/Details/FungibleTokenDetails+View.swift +++ b/RadixWallet/Features/AssetsFeature/Components/FungibleAssetList/Components/Details/FungibleTokenDetails+View.swift @@ -2,32 +2,6 @@ import ComposableArchitecture import SwiftUI extension FungibleTokenDetails.State { - var viewState: FungibleTokenDetails.ViewState { - .init( - detailsHeader: detailsHeader, - thumbnail: { - let iconURL = resource.metadata.get(\.iconURL, prefetched: ownedFungibleResource?.metadata) - return isXRD ? .success(.xrd) : iconURL.map { .other($0) } - }(), - details: .init( - description: resource.metadata.get(\.description, prefetched: ownedFungibleResource?.metadata), - infoUrl: resource.metadata.infoURL, - resourceAddress: resourceAddress, - isXRD: isXRD, - validatorAddress: nil, - resourceName: resource.metadata.name, - currentSupply: resource.totalSupply.map { $0?.formatted() ?? L10n.AssetDetails.supplyUnkown }, - divisibility: resource.divisibility, - arbitraryDataFields: resource.metadata.arbitraryItems.asDataFields, - behaviors: resource.behaviors, - tags: { - let tags = resource.metadata.get(\.tags, prefetched: ownedFungibleResource?.metadata) - return isXRD ? tags.map { $0 + [.officialRadix] } : tags - }() - ) - ) - } - var detailsHeader: DetailsContainerWithHeaderViewState { .init( title: resource.metadata.get(\.name, prefetched: ownedFungibleResource?.metadata).map { $0 ?? L10n.Account.PoolUnits.unknownPoolUnitName }, @@ -36,40 +10,53 @@ extension FungibleTokenDetails.State { symbol: resource.metadata.get(\.symbol, prefetched: ownedFungibleResource?.metadata) ) } + + var thumbnail: Loadable { + let iconURL = resource.metadata.get(\.iconURL, prefetched: ownedFungibleResource?.metadata) + return isXRD ? .success(.xrd) : iconURL.map { .other($0) } + } + + var details: AssetResourceDetailsSection.ViewState { + .init( + description: resource.metadata.get(\.description, prefetched: ownedFungibleResource?.metadata), + infoUrl: resource.metadata.infoURL, + resourceAddress: resourceAddress, + isXRD: isXRD, + validatorAddress: nil, + resourceName: resource.metadata.name, + currentSupply: resource.totalSupply.map { $0?.formatted() ?? L10n.AssetDetails.supplyUnkown }, + divisibility: resource.divisibility, + arbitraryDataFields: resource.metadata.arbitraryItems.asDataFields, + behaviors: resource.behaviors, + tags: { + let tags = resource.metadata.get(\.tags, prefetched: ownedFungibleResource?.metadata) + return isXRD ? tags.map { $0 + [.officialRadix] } : tags + }() + ) + } } // MARK: - FungibleTokenDetails.View extension FungibleTokenDetails { - struct ViewState: Equatable { - let detailsHeader: DetailsContainerWithHeaderViewState - let thumbnail: Loadable - let details: AssetResourceDetailsSection.ViewState - } - - @MainActor struct View: SwiftUI.View { - private let store: StoreOf - - init(store: StoreOf) { - self.store = store - } + let store: StoreOf var body: some SwiftUI.View { - WithViewStore(store, observe: \.viewState, send: { .view($0) }) { viewStore in - DetailsContainerWithHeaderView(viewState: viewStore.detailsHeader) { - viewStore.send(.closeButtonTapped) + WithPerceptionTracking { + DetailsContainerWithHeaderView(viewState: store.detailsHeader) { + store.send(.view(.closeButtonTapped)) } thumbnailView: { - Thumbnail(token: viewStore.thumbnail.wrappedValue ?? .other(nil), size: .veryLarge) + Thumbnail(token: store.thumbnail.wrappedValue ?? .other(nil), size: .veryLarge) } detailsView: { VStack(spacing: .medium1) { - AssetResourceDetailsSection(viewState: viewStore.details) + AssetResourceDetailsSection(viewState: store.details) HideResource.View(store: store.hideResource) } .padding(.bottom, .medium1) } .task { @MainActor in - await viewStore.send(.task).finish() + await store.send(.view(.task)).finish() } } } diff --git a/RadixWallet/Features/InteractionReview/Destinations/UnknownDappComponents/UnknownDappComponents+View.swift b/RadixWallet/Features/InteractionReview/Destinations/UnknownDappComponents/UnknownDappComponents+View.swift index 7540d15369..b9749ce3ab 100644 --- a/RadixWallet/Features/InteractionReview/Destinations/UnknownDappComponents/UnknownDappComponents+View.swift +++ b/RadixWallet/Features/InteractionReview/Destinations/UnknownDappComponents/UnknownDappComponents+View.swift @@ -3,16 +3,18 @@ extension InteractionReview.UnknownDappComponents { let store: StoreOf var body: some SwiftUI.View { - ScrollView { - ForEach(store.addresses, id: \.address) { address in - row(address, heading: store.rowHeading) + WithPerceptionTracking { + ScrollView { + ForEach(store.addresses, id: \.address) { address in + row(address, heading: store.rowHeading) + } } - } - .radixToolbar(title: store.title, alwaysVisible: false) - .toolbar { - ToolbarItem(placement: .cancellationAction) { - CloseButton { - store.send(.view(.closeButtonTapped)) + .radixToolbar(title: store.title, alwaysVisible: false) + .toolbar { + ToolbarItem(placement: .cancellationAction) { + CloseButton { + store.send(.view(.closeButtonTapped)) + } } } } From 6b895195bcac938d974cbb4a150e9045c5ff075b Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 22 Oct 2024 19:14:24 -0300 Subject: [PATCH 26/63] Non Fungible Details as well --- .../NonFungibleTokenDetails+Reducer.swift | 4 + .../NonFungibleTokenDetails+View.swift | 93 +++++++++---------- 2 files changed, 46 insertions(+), 51 deletions(-) diff --git a/RadixWallet/Features/AssetsFeature/Components/NonFungibleAssetList/Components/Details/NonFungibleTokenDetails+Reducer.swift b/RadixWallet/Features/AssetsFeature/Components/NonFungibleAssetList/Components/Details/NonFungibleTokenDetails+Reducer.swift index 95c17b4eeb..44e33220a1 100644 --- a/RadixWallet/Features/AssetsFeature/Components/NonFungibleAssetList/Components/Details/NonFungibleTokenDetails+Reducer.swift +++ b/RadixWallet/Features/AssetsFeature/Components/NonFungibleAssetList/Components/Details/NonFungibleTokenDetails+Reducer.swift @@ -2,7 +2,9 @@ import ComposableArchitecture import SwiftUI // MARK: - NonFungibleTokenDetails +@Reducer struct NonFungibleTokenDetails: Sendable, FeatureReducer { + @ObservableState struct State: Sendable, Hashable { let resourceAddress: ResourceAddress var resourceDetails: Loadable @@ -35,6 +37,8 @@ struct NonFungibleTokenDetails: Sendable, FeatureReducer { } } + typealias Action = FeatureAction + enum ViewAction: Sendable, Equatable { case closeButtonTapped case task diff --git a/RadixWallet/Features/AssetsFeature/Components/NonFungibleAssetList/Components/Details/NonFungibleTokenDetails+View.swift b/RadixWallet/Features/AssetsFeature/Components/NonFungibleAssetList/Components/Details/NonFungibleTokenDetails+View.swift index 34a9009ae5..26f6b5d7a9 100644 --- a/RadixWallet/Features/AssetsFeature/Components/NonFungibleAssetList/Components/Details/NonFungibleTokenDetails+View.swift +++ b/RadixWallet/Features/AssetsFeature/Components/NonFungibleAssetList/Components/Details/NonFungibleTokenDetails+View.swift @@ -2,31 +2,43 @@ import ComposableArchitecture import SwiftUI extension NonFungibleTokenDetails.State { - var viewState: NonFungibleTokenDetails.ViewState { + var tokenDetails: TokenDetails? { + token.map { + .init(token: $0, stakeClaim: stakeClaim) + } + } + + var resourceThumbnail: Loadable { + ownedResource.map { .success($0.metadata.iconURL) } ?? resourceDetails.metadata.iconURL + } + + var resourceDetailsViewState: AssetResourceDetailsSection.ViewState { .init( - tokenDetails: token.map { - NonFungibleTokenDetails.ViewState.TokenDetails(token: $0, stakeClaim: stakeClaim) - }, - resourceThumbnail: ownedResource.map { .success($0.metadata.iconURL) } ?? resourceDetails.metadata.iconURL, - resourceDetails: .init( - description: resourceDetails.metadata.description, - infoUrl: resourceDetails.metadata.infoURL, - resourceAddress: resourceAddress, - isXRD: false, - validatorAddress: nil, - resourceName: resourceDetails.metadata.name, - currentSupply: resourceDetails.totalSupply.map { $0?.formatted() }, - divisibility: nil, - arbitraryDataFields: resourceDetails.metadata.arbitraryItems.asDataFields, - behaviors: resourceDetails.behaviors, - tags: ownedResource.map { .success($0.metadata.tags) } ?? resourceDetails.metadata.tags - ), - isClaimStakeEnabled: isClaimStakeEnabled + description: resourceDetails.metadata.description, + infoUrl: resourceDetails.metadata.infoURL, + resourceAddress: resourceAddress, + isXRD: false, + validatorAddress: nil, + resourceName: resourceDetails.metadata.name, + currentSupply: resourceDetails.totalSupply.map { $0?.formatted() }, + divisibility: nil, + arbitraryDataFields: resourceDetails.metadata.arbitraryItems.asDataFields, + behaviors: resourceDetails.behaviors, + tags: ownedResource.map { .success($0.metadata.tags) } ?? resourceDetails.metadata.tags ) } + + struct TokenDetails: Equatable { + let keyImage: URL? + let nonFungibleGlobalID: NonFungibleGlobalId + let name: String? + let description: String? + let stakeClaim: OnLedgerEntitiesClient.StakeClaim? + let dataFields: [ArbitraryDataField] + } } -extension NonFungibleTokenDetails.ViewState.TokenDetails { +extension NonFungibleTokenDetails.State.TokenDetails { init(token: OnLedgerEntity.NonFungibleToken, stakeClaim: OnLedgerEntitiesClient.StakeClaim?) { self.init( keyImage: token.data?.keyImageURL, @@ -39,39 +51,18 @@ extension NonFungibleTokenDetails.ViewState.TokenDetails { } } -// MARK: - NonFungibleTokenList.Detail.View +// MARK: - NonFungibleTokenDetails.View extension NonFungibleTokenDetails { - struct ViewState: Equatable { - let tokenDetails: TokenDetails? - let resourceThumbnail: Loadable - let resourceDetails: AssetResourceDetailsSection.ViewState - let isClaimStakeEnabled: Bool - - struct TokenDetails: Equatable { - let keyImage: URL? - let nonFungibleGlobalID: NonFungibleGlobalId - let name: String? - let description: String? - let stakeClaim: OnLedgerEntitiesClient.StakeClaim? - let dataFields: [ArbitraryDataField] - } - } - - @MainActor struct View: SwiftUI.View { - private let store: StoreOf - - init(store: StoreOf) { - self.store = store - } + let store: StoreOf var body: some SwiftUI.View { - WithViewStore(store, observe: \.viewState, send: { .view($0) }) { viewStore in - DetailsContainer(title: .success(viewStore.tokenDetails?.name ?? "")) { + WithPerceptionTracking { + DetailsContainer(title: .success(store.tokenDetails?.name ?? "")) { store.send(.view(.closeButtonTapped)) } contents: { VStack(spacing: .zero) { - if let tokenDetails = viewStore.tokenDetails { + if let tokenDetails = store.tokenDetails { VStack(spacing: .medium3) { if let keyImage = tokenDetails.keyImage { NFTFullView(url: keyImage) @@ -92,8 +83,8 @@ extension NonFungibleTokenDetails { } if let stakeClaim = tokenDetails.stakeClaim { - stakeClaimView(stakeClaim, isClaimStakeEnabled: viewStore.isClaimStakeEnabled) { - viewStore.send(.tappedClaimStake) + stakeClaimView(stakeClaim, isClaimStakeEnabled: store.isClaimStakeEnabled) { + store.send(.view(.tappedClaimStake)) } } @@ -114,11 +105,11 @@ extension NonFungibleTokenDetails { } VStack(spacing: .medium1) { - loadable(viewStore.resourceThumbnail) { url in + loadable(store.resourceThumbnail) { url in Thumbnail(.nft, url: url, size: .veryLarge) } - AssetResourceDetailsSection(viewState: viewStore.resourceDetails) + AssetResourceDetailsSection(viewState: store.resourceDetailsViewState) IfLetStore(store.scope(state: \.hideResource, action: \.child.hideResource)) { store in HideResource.View(store: store) @@ -131,7 +122,7 @@ extension NonFungibleTokenDetails { } .foregroundColor(.app.gray1) .task { @MainActor in - await viewStore.send(.task).finish() + await store.send(.view(.task)).finish() } } } From 955c46f2cc391e18ded93b08387f166c8a6fdf66 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 22 Oct 2024 19:43:44 -0300 Subject: [PATCH 27/63] more changes --- .../Components/PoolUnitDetails+View.swift | 68 +++++++------- .../Components/PoolUnitDetails.swift | 4 + .../Components/LSUDetails+View.swift | 88 +++++++++---------- .../StakeUnitList/Components/LSUDetails.swift | 8 ++ .../Sections/Sections+View.swift | 46 ++++++---- 5 files changed, 113 insertions(+), 101 deletions(-) diff --git a/RadixWallet/Features/AssetsFeature/Components/PoolUnitsList/Components/PoolUnitDetails+View.swift b/RadixWallet/Features/AssetsFeature/Components/PoolUnitsList/Components/PoolUnitDetails+View.swift index f6117cc140..7813a1e8dc 100644 --- a/RadixWallet/Features/AssetsFeature/Components/PoolUnitsList/Components/PoolUnitDetails+View.swift +++ b/RadixWallet/Features/AssetsFeature/Components/PoolUnitsList/Components/PoolUnitDetails+View.swift @@ -2,53 +2,47 @@ import ComposableArchitecture import SwiftUI extension PoolUnitDetails.State { - var viewState: PoolUnitDetails.ViewState { + var containerWithHeader: DetailsContainerWithHeaderViewState { + .init(resourcesDetails.poolUnitResource) + } + + var thumbnailURL: URL? { + resourcesDetails.poolUnitResource.resource.metadata.iconURL + } + + var resources: [ResourceBalance.ViewState.Fungible] { + .init(resources: resourcesDetails) + } + + var resourceDetails: AssetResourceDetailsSection.ViewState { let resource = resourcesDetails.poolUnitResource.resource return .init( - containerWithHeader: .init(resourcesDetails.poolUnitResource), - thumbnailURL: resource.metadata.iconURL, - resources: .init(resources: resourcesDetails), - resourceDetails: .init( - description: .success(resource.metadata.description), - infoUrl: .success(resource.metadata.infoURL), - resourceAddress: resource.resourceAddress, - isXRD: false, - validatorAddress: nil, - resourceName: .success(resource.metadata.name), - currentSupply: .success(resource.totalSupply?.formatted() ?? L10n.AssetDetails.supplyUnkown), - divisibility: .success(resource.divisibility), - arbitraryDataFields: .success(resource.metadata.arbitraryItems.asDataFields), - behaviors: .success(resource.behaviors), - tags: .success(resource.metadata.tags) - ) + description: .success(resource.metadata.description), + infoUrl: .success(resource.metadata.infoURL), + resourceAddress: resource.resourceAddress, + isXRD: false, + validatorAddress: nil, + resourceName: .success(resource.metadata.name), + currentSupply: .success(resource.totalSupply?.formatted() ?? L10n.AssetDetails.supplyUnkown), + divisibility: .success(resource.divisibility), + arbitraryDataFields: .success(resource.metadata.arbitraryItems.asDataFields), + behaviors: .success(resource.behaviors), + tags: .success(resource.metadata.tags) ) } } // MARK: - PoolUnitDetails.View extension PoolUnitDetails { - struct ViewState: Equatable { - let containerWithHeader: DetailsContainerWithHeaderViewState - let thumbnailURL: URL? - let resources: [ResourceBalance.ViewState.Fungible] - - let resourceDetails: AssetResourceDetailsSection.ViewState - } - - @MainActor struct View: SwiftUI.View { - private let store: StoreOf - - init(store: StoreOf) { - self.store = store - } + let store: StoreOf var body: some SwiftUI.View { - WithViewStore(store, observe: \.viewState, send: { .view($0) }) { viewStore in - DetailsContainerWithHeaderView(viewState: viewStore.containerWithHeader) { - viewStore.send(.closeButtonTapped) + WithPerceptionTracking { + DetailsContainerWithHeaderView(viewState: store.containerWithHeader) { + store.send(.view(.closeButtonTapped)) } thumbnailView: { - Thumbnail(.poolUnit, url: viewStore.thumbnailURL, size: .veryLarge) + Thumbnail(.poolUnit, url: store.thumbnailURL, size: .veryLarge) } detailsView: { VStack(spacing: .medium1) { AssetDetailsSeparator() @@ -57,10 +51,10 @@ extension PoolUnitDetails { .textStyle(.secondaryHeader) .foregroundColor(.app.gray1) - ResourceBalancesView(fungibles: viewStore.resources) + ResourceBalancesView(fungibles: store.resources) .padding(.horizontal, .large2) - AssetResourceDetailsSection(viewState: viewStore.resourceDetails) + AssetResourceDetailsSection(viewState: store.resourceDetails) HideResource.View(store: store.hideResource) } diff --git a/RadixWallet/Features/AssetsFeature/Components/PoolUnitsList/Components/PoolUnitDetails.swift b/RadixWallet/Features/AssetsFeature/Components/PoolUnitsList/Components/PoolUnitDetails.swift index 375a31475f..8c9455dd90 100644 --- a/RadixWallet/Features/AssetsFeature/Components/PoolUnitsList/Components/PoolUnitDetails.swift +++ b/RadixWallet/Features/AssetsFeature/Components/PoolUnitsList/Components/PoolUnitDetails.swift @@ -2,7 +2,9 @@ import ComposableArchitecture import SwiftUI // MARK: - PoolUnitDetails +@Reducer struct PoolUnitDetails: Sendable, FeatureReducer { + @ObservableState struct State: Sendable, Hashable { let resourcesDetails: OnLedgerEntitiesClient.OwnedResourcePoolDetails var hideResource: HideResource.State @@ -15,6 +17,8 @@ struct PoolUnitDetails: Sendable, FeatureReducer { @Dependency(\.dismiss) var dismiss + typealias Action = FeatureAction + enum ViewAction: Sendable, Equatable { case closeButtonTapped } diff --git a/RadixWallet/Features/AssetsFeature/Components/StakeUnitList/Components/LSUDetails+View.swift b/RadixWallet/Features/AssetsFeature/Components/StakeUnitList/Components/LSUDetails+View.swift index 29aaee5716..86d455b778 100644 --- a/RadixWallet/Features/AssetsFeature/Components/StakeUnitList/Components/LSUDetails+View.swift +++ b/RadixWallet/Features/AssetsFeature/Components/StakeUnitList/Components/LSUDetails+View.swift @@ -2,61 +2,55 @@ import ComposableArchitecture import SwiftUI extension LSUDetails.State { - var viewState: LSUDetails.ViewState { + var containerWithHeader: DetailsContainerWithHeaderViewState { .init( - containerWithHeader: .init( - title: .success(stakeUnitResource.resource.metadata.title), - amount: stakeUnitResource.amount.nominalAmount.formatted(), - currencyWorth: nil, - symbol: .success(stakeUnitResource.resource.metadata.symbol) - ), - thumbnailURL: stakeUnitResource.resource.metadata.iconURL, - validatorNameViewState: .init(with: validator), - redeemableTokenAmount: .xrd(balance: xrdRedemptionValue, network: validator.address.networkID), - resourceDetails: .init( - description: .success(stakeUnitResource.resource.metadata.description), - infoUrl: .success(stakeUnitResource.resource.metadata.infoURL), - resourceAddress: stakeUnitResource.resource.resourceAddress, - isXRD: false, - validatorAddress: validator.address, - resourceName: .success(stakeUnitResource.resource.metadata.title), - currentSupply: .success(validator.xrdVaultBalance.formatted()), - divisibility: .success(stakeUnitResource.resource.divisibility), - arbitraryDataFields: .success(stakeUnitResource.resource.metadata.arbitraryItems.asDataFields), - behaviors: .success(stakeUnitResource.resource.behaviors), - tags: .success(stakeUnitResource.resource.metadata.tags) - ) + title: .success(stakeUnitResource.resource.metadata.title), + amount: stakeUnitResource.amount.nominalAmount.formatted(), + currencyWorth: nil, + symbol: .success(stakeUnitResource.resource.metadata.symbol) ) } -} -extension LSUDetails { - struct ViewState: Equatable { - let containerWithHeader: DetailsContainerWithHeaderViewState - let thumbnailURL: URL? + var thumbnailURL: URL? { + stakeUnitResource.resource.metadata.iconURL + } - let validatorNameViewState: ValidatorHeaderView.ViewState - let redeemableTokenAmount: ResourceBalance.ViewState.Fungible - let resourceDetails: AssetResourceDetailsSection.ViewState + var validatorNameViewState: ValidatorHeaderView.ViewState { + .init(with: validator) } - struct View: SwiftUI.View { - private let store: StoreOf + var redeemableTokenAmount: ResourceBalance.ViewState.Fungible { + .xrd(balance: xrdRedemptionValue, network: validator.address.networkID) + } - init(store: StoreOf) { - self.store = store - } + var resourceDetails: AssetResourceDetailsSection.ViewState { + .init( + description: .success(stakeUnitResource.resource.metadata.description), + infoUrl: .success(stakeUnitResource.resource.metadata.infoURL), + resourceAddress: stakeUnitResource.resource.resourceAddress, + isXRD: false, + validatorAddress: validator.address, + resourceName: .success(stakeUnitResource.resource.metadata.title), + currentSupply: .success(validator.xrdVaultBalance.formatted()), + divisibility: .success(stakeUnitResource.resource.divisibility), + arbitraryDataFields: .success(stakeUnitResource.resource.metadata.arbitraryItems.asDataFields), + behaviors: .success(stakeUnitResource.resource.behaviors), + tags: .success(stakeUnitResource.resource.metadata.tags) + ) + } +} + +// MARK: - LSUDetails.View +extension LSUDetails { + struct View: SwiftUI.View { + let store: StoreOf var body: some SwiftUI.View { - WithViewStore( - store, - observe: \.viewState, - send: LSUDetails.Action.view - ) { viewStore in - DetailsContainerWithHeaderView(viewState: viewStore.containerWithHeader) { - viewStore.send(.closeButtonTapped) + WithPerceptionTracking { + DetailsContainerWithHeaderView(viewState: store.containerWithHeader) { + store.send(.view(.closeButtonTapped)) } thumbnailView: { - Thumbnail(.nft, url: viewStore.thumbnailURL, size: .veryLarge) + Thumbnail(.nft, url: store.thumbnailURL, size: .veryLarge) } detailsView: { VStack(spacing: .medium1) { AssetDetailsSeparator() @@ -65,13 +59,13 @@ extension LSUDetails { .textStyle(.secondaryHeader) .foregroundColor(.app.gray1) - ValidatorHeaderView(viewState: viewStore.validatorNameViewState) + ValidatorHeaderView(viewState: store.validatorNameViewState) .padding(.horizontal, .large2) - ResourceBalanceView(.fungible(viewStore.redeemableTokenAmount), appearance: .compact(border: true)) + ResourceBalanceView(.fungible(store.redeemableTokenAmount), appearance: .compact(border: true)) .padding(.horizontal, .large2) - AssetResourceDetailsSection(viewState: viewStore.resourceDetails) + AssetResourceDetailsSection(viewState: store.resourceDetails) } .padding(.bottom, .medium1) } diff --git a/RadixWallet/Features/AssetsFeature/Components/StakeUnitList/Components/LSUDetails.swift b/RadixWallet/Features/AssetsFeature/Components/StakeUnitList/Components/LSUDetails.swift index 4c266551b3..708b561035 100644 --- a/RadixWallet/Features/AssetsFeature/Components/StakeUnitList/Components/LSUDetails.swift +++ b/RadixWallet/Features/AssetsFeature/Components/StakeUnitList/Components/LSUDetails.swift @@ -2,7 +2,9 @@ import ComposableArchitecture import SwiftUI // MARK: - LSUDetails +@Reducer struct LSUDetails: Sendable, FeatureReducer { + @ObservableState struct State: Sendable, Hashable { let validator: OnLedgerEntity.Validator let stakeUnitResource: OnLedgerEntitiesClient.ResourceWithVaultAmount @@ -11,10 +13,16 @@ struct LSUDetails: Sendable, FeatureReducer { @Dependency(\.dismiss) var dismiss + typealias Action = FeatureAction + enum ViewAction: Sendable, Equatable { case closeButtonTapped } + var body: some ReducerOf { + Reduce(core) + } + func reduce(into state: inout State, viewAction: ViewAction) -> Effect { switch viewAction { case .closeButtonTapped: diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift index f4b340aeeb..bd68f9b5b0 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift @@ -194,44 +194,56 @@ private extension View { } private func dApp(with destinationStore: PresentationStoreOf) -> some View { - sheet(store: destinationStore.scope(state: \.dApp, action: \.dApp)) { detailsStore in - WithNavigationBar { - destinationStore.send(.dismiss) - } content: { - DappDetails.View(store: detailsStore) + WithPerceptionTracking { + sheet(store: destinationStore.scope(state: \.dApp, action: \.dApp)) { detailsStore in + WithNavigationBar { + destinationStore.send(.dismiss) + } content: { + DappDetails.View(store: detailsStore) + } } } } private func unknownComponents(with destinationStore: PresentationStoreOf) -> some View { - sheet(store: destinationStore.scope(state: \.unknownDappComponents, action: \.unknownDappComponents)) { - InteractionReview.UnknownDappComponents.View(store: $0) - .inNavigationStack - .presentationDetents([.medium]) + WithPerceptionTracking { + sheet(store: destinationStore.scope(state: \.unknownDappComponents, action: \.unknownDappComponents)) { + InteractionReview.UnknownDappComponents.View(store: $0) + .inNavigationStack + .presentationDetents([.medium]) + } } } private func fungibleTokenDetails(with destinationStore: PresentationStoreOf) -> some View { - sheet(store: destinationStore.scope(state: \.fungibleTokenDetails, action: \.fungibleTokenDetails)) { - FungibleTokenDetails.View(store: $0) + WithPerceptionTracking { + sheet(store: destinationStore.scope(state: \.fungibleTokenDetails, action: \.fungibleTokenDetails)) { + FungibleTokenDetails.View(store: $0) + } } } private func nonFungibleTokenDetails(with destinationStore: PresentationStoreOf) -> some View { - sheet(store: destinationStore.scope(state: \.nonFungibleTokenDetails, action: \.nonFungibleTokenDetails)) { - NonFungibleTokenDetails.View(store: $0) + WithPerceptionTracking { + sheet(store: destinationStore.scope(state: \.nonFungibleTokenDetails, action: \.nonFungibleTokenDetails)) { + NonFungibleTokenDetails.View(store: $0) + } } } private func lsuDetails(with destinationStore: PresentationStoreOf) -> some View { - sheet(store: destinationStore.scope(state: \.lsuDetails, action: \.lsuDetails)) { - LSUDetails.View(store: $0) + WithPerceptionTracking { + sheet(store: destinationStore.scope(state: \.lsuDetails, action: \.lsuDetails)) { + LSUDetails.View(store: $0) + } } } private func poolUnitDetails(with destinationStore: PresentationStoreOf) -> some View { - sheet(store: destinationStore.scope(state: \.poolUnitDetails, action: \.poolUnitDetails)) { - PoolUnitDetails.View(store: $0) + WithPerceptionTracking { + sheet(store: destinationStore.scope(state: \.poolUnitDetails, action: \.poolUnitDetails)) { + PoolUnitDetails.View(store: $0) + } } } } From 5e5af4ad937ba3575d9bb9c948cc2e832d9fcdb2 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Wed, 23 Oct 2024 08:27:41 -0300 Subject: [PATCH 28/63] migrate PreAuthorizationReview & Sections to old way --- .../Sections/Sections+View.swift | 104 +++++++++++------- .../InteractionReview/Sections/Sections.swift | 4 +- .../PreAuthorizationReview+View.swift | 95 ++++++++++------ .../PreAuthorizationReview.swift | 8 +- 4 files changed, 129 insertions(+), 82 deletions(-) diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift index bd68f9b5b0..91e7011bb5 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift @@ -1,50 +1,83 @@ import SwiftUI +extension InteractionReview.Sections.State { + var viewState: InteractionReview.Sections.ViewState { + .init( + isExpandedDappsUsed: dAppsUsed?.isExpanded == true, + isExpandedContributingToPools: contributingToPools?.isExpanded == true, + isExpandedRedeemingFromPools: redeemingFromPools?.isExpanded == true, + showTransferLine: withdrawals != nil && deposits != nil, + stakingToValidators: stakingToValidators, + unstakingFromValidators: unstakingFromValidators, + claimingFromValidators: claimingFromValidators, + accountDepositSetting: accountDepositSetting, + accountDepositExceptions: accountDepositExceptions + ) + } +} + // MARK: - InteractionReview.Sections.View extension InteractionReview.Sections { + struct ViewState: Equatable { + let isExpandedDappsUsed: Bool + let isExpandedContributingToPools: Bool + let isExpandedRedeemingFromPools: Bool + let showTransferLine: Bool + + let stakingToValidators: InteractionReview.ValidatorsState? + let unstakingFromValidators: InteractionReview.ValidatorsState? + let claimingFromValidators: InteractionReview.ValidatorsState? + let accountDepositSetting: InteractionReview.DepositSettingState? + let accountDepositExceptions: InteractionReview.DepositExceptionsState? + + var isExpandedStakingToValidators: Bool { stakingToValidators?.isExpanded == true } + var isExpandedUnstakingFromValidators: Bool { unstakingFromValidators?.isExpanded == true } + var isExpandedClaimingFromValidators: Bool { claimingFromValidators?.isExpanded == true } + } + struct View: SwiftUI.View { let store: StoreOf var body: some SwiftUI.View { - WithPerceptionTracking { + WithViewStore(store, observe: \.viewState, send: { .view($0) }) { viewStore in VStack(alignment: .leading, spacing: .medium1) { withdrawals VStack(alignment: .leading, spacing: .medium1) { - contributingToPools - redeemingFromPools + contributingToPools(viewStore.isExpandedContributingToPools) + redeemingFromPools(viewStore.isExpandedRedeemingFromPools) - stakingToValidators - unstakingFromValidators - claimingFromValidators + stakingToValidators(viewStore.stakingToValidators) + unstakingFromValidators(viewStore.unstakingFromValidators) + claimingFromValidators(viewStore.claimingFromValidators) - dAppsUsed + dAppsUsed(viewStore.isExpandedDappsUsed) deposits } .frame(maxWidth: .infinity, alignment: .leading) // necessary? .background(alignment: .trailing) { - if store.showTransferLine { + if viewStore.showTransferLine { Common.TransferLineView() } } - accountDepositSetting - accountDepositExceptions + accountDepositSetting(viewStore.accountDepositSetting) + accountDepositExceptions(viewStore.accountDepositExceptions) } - .animation(.easeInOut, value: store.contributingToPools?.isExpanded) - .animation(.easeInOut, value: store.redeemingFromPools?.isExpanded) - .animation(.easeInOut, value: store.stakingToValidators?.isExpanded) - .animation(.easeInOut, value: store.unstakingFromValidators?.isExpanded) - .animation(.easeInOut, value: store.claimingFromValidators?.isExpanded) - .animation(.easeInOut, value: store.dAppsUsed?.isExpanded) + .animation(.easeInOut, value: viewStore.isExpandedDappsUsed) + .animation(.easeInOut, value: viewStore.isExpandedContributingToPools) + .animation(.easeInOut, value: viewStore.isExpandedRedeemingFromPools) + .animation(.easeInOut, value: viewStore.isExpandedStakingToValidators) + .animation(.easeInOut, value: viewStore.isExpandedUnstakingFromValidators) + .animation(.easeInOut, value: viewStore.isExpandedClaimingFromValidators) } .destinations(with: store) } @ViewBuilder private var withdrawals: some SwiftUI.View { - if let childStore = store.scope(state: \.withdrawals, action: \.child.withdrawals) { + IfLetStore(store.scope(state: \.withdrawals, action: \.child.withdrawals)) { childStore in VStack(alignment: .leading, spacing: .small2) { Common.HeadingView.withdrawing Common.Accounts.View(store: childStore) @@ -53,10 +86,9 @@ extension InteractionReview.Sections { } @ViewBuilder - private var contributingToPools: some SwiftUI.View { - if let childStore = store.scope(state: \.contributingToPools, action: \.child.contributingToPools) { + private func contributingToPools(_ isExpanded: Bool) -> some SwiftUI.View { + IfLetStore(store.scope(state: \.contributingToPools, action: \.child.contributingToPools)) { childStore in VStack(alignment: .leading, spacing: .small2) { - let isExpanded = childStore.isExpanded Common.ExpandableHeadingView(heading: .contributingToPools, isExpanded: isExpanded) { store.send(.view(.expandableItemToggled(.contributingToPools))) } @@ -69,10 +101,9 @@ extension InteractionReview.Sections { } @ViewBuilder - private var redeemingFromPools: some SwiftUI.View { - if let childStore = store.scope(state: \.redeemingFromPools, action: \.child.redeemingFromPools) { + private func redeemingFromPools(_ isExpanded: Bool) -> some SwiftUI.View { + IfLetStore(store.scope(state: \.redeemingFromPools, action: \.child.redeemingFromPools)) { childStore in VStack(alignment: .leading, spacing: .small2) { - let isExpanded = childStore.isExpanded Common.ExpandableHeadingView(heading: .redeemingFromPools, isExpanded: isExpanded) { store.send(.view(.expandableItemToggled(.redeemingFromPools))) } @@ -85,8 +116,8 @@ extension InteractionReview.Sections { } @ViewBuilder - private var stakingToValidators: some SwiftUI.View { - if let viewState = store.stakingToValidators { + private func stakingToValidators(_ viewState: InteractionReview.ValidatorsState?) -> some SwiftUI.View { + if let viewState { Common.ValidatorsView(heading: .stakingToValidators, viewState: viewState) { store.send(.view(.expandableItemToggled(.stakingToValidators))) } @@ -94,8 +125,8 @@ extension InteractionReview.Sections { } @ViewBuilder - private var unstakingFromValidators: some SwiftUI.View { - if let viewState = store.unstakingFromValidators { + private func unstakingFromValidators(_ viewState: InteractionReview.ValidatorsState?) -> some SwiftUI.View { + if let viewState { Common.ValidatorsView(heading: .unstakingFromValidators, viewState: viewState) { store.send(.view(.expandableItemToggled(.unstakingFromValidators))) } @@ -103,8 +134,8 @@ extension InteractionReview.Sections { } @ViewBuilder - private var claimingFromValidators: some SwiftUI.View { - if let viewState = store.claimingFromValidators { + private func claimingFromValidators(_ viewState: InteractionReview.ValidatorsState?) -> some SwiftUI.View { + if let viewState { Common.ValidatorsView(heading: .claimingFromValidators, viewState: viewState) { store.send(.view(.expandableItemToggled(.claimingFromValidators))) } @@ -112,8 +143,8 @@ extension InteractionReview.Sections { } @ViewBuilder - private var accountDepositSetting: some SwiftUI.View { - if let viewState = store.accountDepositSetting { + private func accountDepositSetting(_ viewState: InteractionReview.DepositSettingState?) -> some SwiftUI.View { + if let viewState { VStack(alignment: .leading, spacing: .small2) { Common.HeadingView.depositSetting Common.DepositSettingView(viewState: viewState) @@ -122,8 +153,8 @@ extension InteractionReview.Sections { } @ViewBuilder - private var accountDepositExceptions: some SwiftUI.View { - if let viewState = store.accountDepositExceptions { + private func accountDepositExceptions(_ viewState: InteractionReview.DepositExceptionsState?) -> some SwiftUI.View { + if let viewState { VStack(alignment: .leading, spacing: .small2) { Common.HeadingView.depositExceptions Common.DepositExceptionsView(viewState: viewState) @@ -132,10 +163,9 @@ extension InteractionReview.Sections { } @ViewBuilder - private var dAppsUsed: some SwiftUI.View { - if let childStore = store.scope(state: \.dAppsUsed, action: \.child.dAppsUsed) { + private func dAppsUsed(_ isExpanded: Bool) -> some SwiftUI.View { + IfLetStore(store.scope(state: \.dAppsUsed, action: \.child.dAppsUsed)) { childStore in VStack(alignment: .leading, spacing: .small2) { - let isExpanded = childStore.isExpanded Common.ExpandableHeadingView(heading: .usingDapps, isExpanded: isExpanded) { store.send(.view(.expandableItemToggled(.dAppsUsed))) } @@ -149,7 +179,7 @@ extension InteractionReview.Sections { @ViewBuilder private var deposits: some SwiftUI.View { - if let childStore = store.scope(state: \.deposits, action: \.child.deposits) { + IfLetStore(store.scope(state: \.deposits, action: \.child.deposits)) { childStore in VStack(alignment: .leading, spacing: .small2) { Common.HeadingView.depositing Common.Accounts.View(store: childStore) diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections.swift b/RadixWallet/Features/InteractionReview/Sections/Sections.swift index 6d2efcdb86..a466368303 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections.swift @@ -1,10 +1,8 @@ // MARK: - InteractionReview.Sections extension InteractionReview { - @Reducer struct Sections: Sendable, FeatureReducer { typealias Common = InteractionReview - @ObservableState struct State: Sendable, Hashable { var withdrawals: Accounts.State? = nil var dAppsUsed: InteractionReviewDappsUsed.State? = nil @@ -23,7 +21,7 @@ extension InteractionReview { // The proofs are set here (within the resolve logic) but should be rendered and handled by the parent view, since they may be placed outside the Sections. var proofs: Proofs.State? = nil - @Presents + @PresentationState var destination: Destination.State? = nil } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index d90847bbe7..cefbb00f28 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -1,7 +1,31 @@ import SwiftUI +extension PreAuthorizationReview.State { + var viewState: PreAuthorizationReview.ViewState { + .init( + dAppName: dAppName, + dAppThumbnail: dAppThumbnail, + displayMode: displayMode, + sliderResetDate: sliderResetDate, + expiration: expiration, + secondsToExpiration: secondsToExpiration, + sliderControlState: sliderControlState + ) + } +} + // MARK: - PreAuthorizationReview.View extension PreAuthorizationReview { + struct ViewState: Equatable { + let dAppName: String? + let dAppThumbnail: URL? + let displayMode: Common.DisplayMode + let sliderResetDate: Date + let expiration: Expiration? + let secondsToExpiration: Int? + let sliderControlState: ControlState + } + struct View: SwiftUI.View { let store: StoreOf @@ -12,13 +36,13 @@ extension PreAuthorizationReview { private let showTitleHysteresis: CGFloat = .small3 var body: some SwiftUI.View { - WithPerceptionTracking { - content + WithViewStore(store, observe: \.viewState, send: { .view($0) }) { viewStore in + content(viewStore) .background(.app.white) .toolbar { ToolbarItem(placement: .principal) { if showNavigationTitle { - navigationTitle + navigationTitle(dAppName: viewStore.dAppName) } } } @@ -28,27 +52,27 @@ extension PreAuthorizationReview { } } - private var navigationTitle: some SwiftUI.View { + private func navigationTitle(dAppName: String?) -> some SwiftUI.View { VStack(spacing: .zero) { Text("Review your Pre-Authorization") .textStyle(.body2Header) .foregroundColor(.app.gray1) - if let name = store.dappName { - Text("Proposed by \(name)") + if let dAppName { + Text("Proposed by \(dAppName)") .textStyle(.body2Regular) .foregroundColor(.app.gray2) } } } - private var content: some SwiftUI.View { + private func content(_ viewStore: ViewStoreOf) -> some SwiftUI.View { ScrollView(showsIndicators: false) { VStack(spacing: .zero) { - header + header(dAppName: viewStore.dAppName, dAppThumbnail: viewStore.dAppThumbnail) Group { - if let rawContent = store.displayMode.rawTransaction { + if let rawContent = viewStore.displayMode.rawTransaction { rawTransaction(rawContent) } else { details @@ -58,15 +82,20 @@ extension PreAuthorizationReview { .clipShape(RoundedRectangle(cornerRadius: .small1)) .padding(.horizontal, .small2) - feesInformation + feesInformation(dAppName: viewStore.dAppName) .padding(.top, .small2) .padding(.horizontal, .small2) - expiration + expiration(viewStore.expiration, secondsToExpiration: viewStore.secondsToExpiration) - slider + ApprovalSlider( + title: "Slide to sign and return", + resetDate: viewStore.sliderResetDate + ) {} + .controlState(viewStore.sliderControlState) + .padding(.horizontal, .medium2) } - .animation(.easeInOut, value: store.displayMode.rawTransaction) + .animation(.easeInOut, value: viewStore.displayMode.rawTransaction) } .coordinateSpace(name: coordSpace) .onPreferenceChange(PositionsPreferenceKey.self) { positions in @@ -82,11 +111,11 @@ extension PreAuthorizationReview { } } - private var header: some SwiftUI.View { + private func header(dAppName: String?, dAppThumbnail: URL?) -> some SwiftUI.View { Common.HeaderView( kind: .preAuthorization, - name: store.dappName, - thumbnail: store.dappThumbnail + name: dAppName, + thumbnail: dAppThumbnail ) .measurePosition(navTitleID, coordSpace: coordSpace) .padding(.horizontal, .medium3) @@ -126,16 +155,16 @@ extension PreAuthorizationReview { @ViewBuilder private var proofs: some SwiftUI.View { - if let childStore = store.scope(state: \.proofs, action: \.child.proofs) { + IfLetStore(store.scope(state: \.proofs, action: \.child.proofs)) { childStore in Common.Proofs.View(store: childStore) .padding(.horizontal, .small3) } } - private var feesInformation: some SwiftUI.View { + private func feesInformation(dAppName: String?) -> some SwiftUI.View { HStack(spacing: .zero) { VStack(alignment: .leading, spacing: .zero) { - Text("Pre-authorization will be returned to \(store.dappName ?? "dApp") for processing.") + Text("Pre-authorization will be returned to \(dAppName ?? "dApp") for processing.") .foregroundStyle(.app.gray1) Text("Network fees will be paid by the dApp") @@ -153,16 +182,12 @@ extension PreAuthorizationReview { .clipShape(RoundedRectangle(cornerRadius: .small1)) } - private var expiration: some SwiftUI.View { + @ViewBuilder + private func expiration(_ expiration: Expiration?, secondsToExpiration: Int?) -> some SwiftUI.View { Group { - switch store.expiration { - case .none: - Color.clear - case let .window(seconds): - let value = formatTime(seconds: seconds) - Text("Valid for **\(value) after approval**") + switch expiration { case .atTime: - if let seconds = store.secondsToExpiration { + if let seconds = secondsToExpiration { if seconds > 0 { let value = formatTime(seconds: seconds) Text("Valid for the next **\(value)**") @@ -170,6 +195,13 @@ extension PreAuthorizationReview { Text("This subintent is no longer valid!") } } + + case let .window(seconds): + let value = formatTime(seconds: seconds) + Text("Valid for **\(value) after approval**") + + case nil: + Color.clear } } .textStyle(.body2Regular) @@ -177,15 +209,6 @@ extension PreAuthorizationReview { .padding(.horizontal, .medium1) .frame(minHeight: .huge2) } - - private var slider: some SwiftUI.View { - ApprovalSlider( - title: "Slide to sign and return", - resetDate: store.sliderResetDate - ) {} - .controlState(store.sliderControlState) - .padding(.horizontal, .medium2) - } } } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 396fb8487e..4ee528e9bd 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -1,12 +1,10 @@ // MARK: - PreAuthorizationReview -@Reducer struct PreAuthorizationReview: Sendable, FeatureReducer { typealias Common = InteractionReview - @ObservableState struct State: Sendable, Hashable { - var dappName: String? = "CaviarNine" - var dappThumbnail: URL? = .init(string: "https://assets.caviarnine.com/icons/caviarnine_logo_light_400.png") + var dAppName: String? = "CaviarNine" + var dAppThumbnail: URL? = .init(string: "https://assets.caviarnine.com/icons/caviarnine_logo_light_400.png") var displayMode: Common.DisplayMode = .detailed var sliderResetDate: Date = .now // TODO: reset when it corresponds @@ -20,8 +18,6 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { init() {} } - typealias Action = FeatureAction - enum ViewAction: Sendable, Equatable { case appeared case toggleDisplayModeButtonTapped From 7fe96f2d442e5e79c64188fd6c221fb044119f06 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Wed, 23 Oct 2024 08:48:18 -0300 Subject: [PATCH 29/63] fix for HideResourceView warning --- .../HideResource/HideResource+View.swift | 8 +- .../NonFungibleTokenDetails+View.swift | 86 ++++++++++--------- 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/RadixWallet/Features/AssetsFeature/Components/HideResource/HideResource+View.swift b/RadixWallet/Features/AssetsFeature/Components/HideResource/HideResource+View.swift index a2700510aa..1c1b6dd501 100644 --- a/RadixWallet/Features/AssetsFeature/Components/HideResource/HideResource+View.swift +++ b/RadixWallet/Features/AssetsFeature/Components/HideResource/HideResource+View.swift @@ -48,9 +48,11 @@ private extension View { } private func confirmation(with destinationStore: PresentationStoreOf, store: StoreOf) -> some View { - sheet(store: destinationStore.scope(state: \.confirmation, action: \.confirmation)) { _ in - ConfirmationView(kind: store.confirmationKind) { action in - store.send(.destination(.presented(.confirmation(action)))) + WithPerceptionTracking { + sheet(store: destinationStore.scope(state: \.confirmation, action: \.confirmation)) { _ in + ConfirmationView(kind: store.confirmationKind) { action in + store.send(.destination(.presented(.confirmation(action)))) + } } } } diff --git a/RadixWallet/Features/AssetsFeature/Components/NonFungibleAssetList/Components/Details/NonFungibleTokenDetails+View.swift b/RadixWallet/Features/AssetsFeature/Components/NonFungibleAssetList/Components/Details/NonFungibleTokenDetails+View.swift index 26f6b5d7a9..76720a0905 100644 --- a/RadixWallet/Features/AssetsFeature/Components/NonFungibleAssetList/Components/Details/NonFungibleTokenDetails+View.swift +++ b/RadixWallet/Features/AssetsFeature/Components/NonFungibleAssetList/Components/Details/NonFungibleTokenDetails+View.swift @@ -61,63 +61,65 @@ extension NonFungibleTokenDetails { DetailsContainer(title: .success(store.tokenDetails?.name ?? "")) { store.send(.view(.closeButtonTapped)) } contents: { - VStack(spacing: .zero) { - if let tokenDetails = store.tokenDetails { - VStack(spacing: .medium3) { - if let keyImage = tokenDetails.keyImage { - NFTFullView(url: keyImage) - } + WithPerceptionTracking { + VStack(spacing: .zero) { + if let tokenDetails = store.tokenDetails { + VStack(spacing: .medium3) { + if let keyImage = tokenDetails.keyImage { + NFTFullView(url: keyImage) + } - if let description = tokenDetails.description { - ExpandableTextView(fullText: description) - .textStyle(.body1Regular) - .foregroundColor(.app.gray1) - AssetDetailsSeparator() - .padding(.horizontal, -.large2) - } + if let description = tokenDetails.description { + ExpandableTextView(fullText: description) + .textStyle(.body1Regular) + .foregroundColor(.app.gray1) + AssetDetailsSeparator() + .padding(.horizontal, -.large2) + } - KeyValueView(nonFungibleGlobalID: tokenDetails.nonFungibleGlobalID, showLocalIdOnly: true) + KeyValueView(nonFungibleGlobalID: tokenDetails.nonFungibleGlobalID, showLocalIdOnly: true) - if let name = tokenDetails.name { - KeyValueView(key: L10n.AssetDetails.NFTDetails.name, value: name) - } + if let name = tokenDetails.name { + KeyValueView(key: L10n.AssetDetails.NFTDetails.name, value: name) + } - if let stakeClaim = tokenDetails.stakeClaim { - stakeClaimView(stakeClaim, isClaimStakeEnabled: store.isClaimStakeEnabled) { - store.send(.view(.tappedClaimStake)) + if let stakeClaim = tokenDetails.stakeClaim { + stakeClaimView(stakeClaim, isClaimStakeEnabled: store.isClaimStakeEnabled) { + store.send(.view(.tappedClaimStake)) + } } - } - if !tokenDetails.dataFields.isEmpty { - AssetDetailsSeparator() - .padding(.horizontal, -.large2) + if !tokenDetails.dataFields.isEmpty { + AssetDetailsSeparator() + .padding(.horizontal, -.large2) - ForEachStatic(tokenDetails.dataFields) { field in - ArbitraryDataFieldView(field: field) + ForEachStatic(tokenDetails.dataFields) { field in + ArbitraryDataFieldView(field: field) + } } } + .lineLimit(1) + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.top, .small1) + .padding(.horizontal, .large2) + .padding(.bottom, .medium1) } - .lineLimit(1) - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.top, .small1) - .padding(.horizontal, .large2) - .padding(.bottom, .medium1) - } - VStack(spacing: .medium1) { - loadable(store.resourceThumbnail) { url in - Thumbnail(.nft, url: url, size: .veryLarge) - } + VStack(spacing: .medium1) { + loadable(store.resourceThumbnail) { url in + Thumbnail(.nft, url: url, size: .veryLarge) + } - AssetResourceDetailsSection(viewState: store.resourceDetailsViewState) + AssetResourceDetailsSection(viewState: store.resourceDetailsViewState) - IfLetStore(store.scope(state: \.hideResource, action: \.child.hideResource)) { store in - HideResource.View(store: store) - .padding(.vertical, .medium1) + if let childStore = store.scope(state: \.hideResource, action: \.child.hideResource) { + HideResource.View(store: childStore) + .padding(.vertical, .medium1) + } } + .padding(.vertical, .medium1) + .background(.app.gray5, ignoresSafeAreaEdges: .bottom) } - .padding(.vertical, .medium1) - .background(.app.gray5, ignoresSafeAreaEdges: .bottom) } } .foregroundColor(.app.gray1) From 5a50a886a43d2638b6bde94a7d8604783355b0ac Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Wed, 23 Oct 2024 09:37:50 -0300 Subject: [PATCH 30/63] show Proofs inside Sections when neccessary --- .../Sections/Sections+View.swift | 14 ++++++++ .../InteractionReview/Sections/Sections.swift | 13 ++++++- .../PreAuthorizationReview+View.swift | 36 ++++++------------- .../PreAuthorizationReview.swift | 23 +----------- .../TransactionReview.swift | 2 +- 5 files changed, 38 insertions(+), 50 deletions(-) diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift index 91e7011bb5..686f335fa4 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift @@ -7,6 +7,7 @@ extension InteractionReview.Sections.State { isExpandedContributingToPools: contributingToPools?.isExpanded == true, isExpandedRedeemingFromPools: redeemingFromPools?.isExpanded == true, showTransferLine: withdrawals != nil && deposits != nil, + showProofs: kind == .preAuthorization, stakingToValidators: stakingToValidators, unstakingFromValidators: unstakingFromValidators, claimingFromValidators: claimingFromValidators, @@ -23,6 +24,7 @@ extension InteractionReview.Sections { let isExpandedContributingToPools: Bool let isExpandedRedeemingFromPools: Bool let showTransferLine: Bool + let showProofs: Bool let stakingToValidators: InteractionReview.ValidatorsState? let unstakingFromValidators: InteractionReview.ValidatorsState? @@ -54,6 +56,10 @@ extension InteractionReview.Sections { dAppsUsed(viewStore.isExpandedDappsUsed) deposits + + if viewStore.showProofs { + proofs + } } .frame(maxWidth: .infinity, alignment: .leading) // necessary? .background(alignment: .trailing) { @@ -186,6 +192,14 @@ extension InteractionReview.Sections { } } } + + @ViewBuilder + private var proofs: some SwiftUI.View { + IfLetStore(store.scope(state: \.proofs, action: \.child.proofs)) { childStore in + Common.Proofs.View(store: childStore) + .padding(.horizontal, .small3) + } + } } } diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections.swift b/RadixWallet/Features/InteractionReview/Sections/Sections.swift index a466368303..f241f1001d 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections.swift @@ -4,6 +4,8 @@ extension InteractionReview { typealias Common = InteractionReview struct State: Sendable, Hashable { + let kind: InteractionReview.Kind + var withdrawals: Accounts.State? = nil var dAppsUsed: InteractionReviewDappsUsed.State? = nil var deposits: Accounts.State? = nil @@ -18,7 +20,7 @@ extension InteractionReview { var accountDepositSetting: InteractionReview.DepositSettingState? = nil var accountDepositExceptions: InteractionReview.DepositExceptionsState? = nil - // The proofs are set here (within the resolve logic) but should be rendered and handled by the parent view, since they may be placed outside the Sections. + // The proofs are set here (within the resolve logic) but may be rendered and handled by the parent view, in the case they are placed outside the Sections (TransactionReview). var proofs: Proofs.State? = nil @PresentationState @@ -54,6 +56,7 @@ extension InteractionReview { case dAppsUsed(InteractionReviewDappsUsed.Action) case contributingToPools(InteractionReviewPools.Action) case redeemingFromPools(InteractionReviewPools.Action) + case proofs(Common.Proofs.Action) } enum DelegateAction: Sendable, Hashable { @@ -131,6 +134,9 @@ extension InteractionReview { .ifLet(\.redeemingFromPools, action: \.child.redeemingFromPools) { InteractionReviewPools() } + .ifLet(\.proofs, action: \.child.proofs) { + Common.Proofs() + } .ifLet(destinationPath, action: /Action.destination) { Destination() } @@ -242,6 +248,11 @@ extension InteractionReview { guard let guarantees = state.deposits?.accounts.customizableGuarantees, !guarantees.isEmpty else { return .none } return .send(.delegate(.showCustomizeGuarantees(guarantees))) + case let .proofs(.delegate(.showAsset(proof))): + let resource = proof.resourceBalance.resource + let details = proof.resourceBalance.details + return resourceDetailsEffect(state: &state, resource: resource, details: details) + default: return .none } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index cefbb00f28..566b1aa012 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -131,21 +131,17 @@ extension PreAuthorizationReview { } private var details: some SwiftUI.View { - VStack(alignment: .leading, spacing: .medium1) { - sections - - proofs - } - .padding(.top, .large2 + .small3) - .padding(.horizontal, .small1) - .padding(.bottom, .medium1) - .overlay(alignment: .topTrailing) { - Button(asset: AssetResource.code) { - store.send(.view(.toggleDisplayModeButtonTapped)) + sections + .padding(.top, .large2 + .small3) + .padding(.horizontal, .small1) + .padding(.bottom, .medium1) + .overlay(alignment: .topTrailing) { + Button(asset: AssetResource.code) { + store.send(.view(.toggleDisplayModeButtonTapped)) + } + .buttonStyle(.secondaryRectangular) + .padding(.medium3) } - .buttonStyle(.secondaryRectangular) - .padding(.medium3) - } } private var sections: some SwiftUI.View { @@ -153,14 +149,6 @@ extension PreAuthorizationReview { return Common.Sections.View(store: childStore) } - @ViewBuilder - private var proofs: some SwiftUI.View { - IfLetStore(store.scope(state: \.proofs, action: \.child.proofs)) { childStore in - Common.Proofs.View(store: childStore) - .padding(.horizontal, .small3) - } - } - private func feesInformation(dAppName: String?) -> some SwiftUI.View { HStack(spacing: .zero) { VStack(alignment: .leading, spacing: .zero) { @@ -240,10 +228,6 @@ private extension PreAuthorizationReview.View { } private extension PreAuthorizationReview.State { - var showTransferLine: Bool { - true - } - var controlState: ControlState { // If is loading transaction show loading .enabled diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 4ee528e9bd..a097cded66 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -12,8 +12,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { var secondsToExpiration: Int? // Sections - var sections: Common.Sections.State = .init() - var proofs: Common.Proofs.State? = nil + var sections: Common.Sections.State = .init(kind: .preAuthorization) init() {} } @@ -27,7 +26,6 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { @CasePathable enum ChildAction: Sendable, Equatable { case sections(Common.Sections.Action) - case proofs(Common.Proofs.Action) } enum InternalAction: Sendable, Equatable { @@ -42,9 +40,6 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { Common.Sections() } Reduce(core) - .ifLet(\.proofs, action: \.child.proofs) { - Common.Proofs() - } } func reduce(into state: inout State, viewAction: ViewAction) -> Effect { @@ -83,22 +78,6 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { return .none } } - - func reduce(into state: inout State, childAction: ChildAction) -> Effect { - switch childAction { - case let .sections(.internal(.setSections(sections))): - state.proofs = sections?.proofs - return .none - - case let .proofs(.delegate(.showAsset(proof))): - let resource = proof.resourceBalance.resource - let details = proof.resourceBalance.details - return .send(.child(.sections(.internal(.parent(.showResourceDetails(resource, details)))))) - - default: - return .none - } - } } private extension PreAuthorizationReview { diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift index 2ceefc23fa..a638a4117d 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift @@ -21,7 +21,7 @@ struct TransactionReview: Sendable, FeatureReducer { var reviewedTransaction: ReviewedTransaction? = nil - var sections: Common.Sections.State = .init() + var sections: Common.Sections.State = .init(kind: .transaction) var proofs: Common.Proofs.State? = nil var networkFee: TransactionReviewNetworkFee.State? = nil From 8de0e95c03329700353b06007ae0b2f14101a530 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Wed, 23 Oct 2024 10:36:53 -0300 Subject: [PATCH 31/63] load dynamic summary --- .../PreAuthorizationReview+View.swift | 10 ++-- .../PreAuthorizationReview.swift | 48 ++++++++++++++----- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index 566b1aa012..bc9c864c1c 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -9,6 +9,7 @@ extension PreAuthorizationReview.State { sliderResetDate: sliderResetDate, expiration: expiration, secondsToExpiration: secondsToExpiration, + globalControlState: globalControlState, sliderControlState: sliderControlState ) } @@ -23,6 +24,7 @@ extension PreAuthorizationReview { let sliderResetDate: Date let expiration: Expiration? let secondsToExpiration: Int? + let globalControlState: ControlState let sliderControlState: ControlState } @@ -38,6 +40,7 @@ extension PreAuthorizationReview { var body: some SwiftUI.View { WithViewStore(store, observe: \.viewState, send: { .view($0) }) { viewStore in content(viewStore) + .controlState(viewStore.globalControlState) .background(.app.white) .toolbar { ToolbarItem(placement: .principal) { @@ -228,12 +231,11 @@ private extension PreAuthorizationReview.View { } private extension PreAuthorizationReview.State { - var controlState: ControlState { - // If is loading transaction show loading - .enabled + var globalControlState: ControlState { + reviewedPreAuthorization != nil ? .enabled : .loading(.global(text: "Incoming PreAuthorization")) } var sliderControlState: ControlState { - isExpired ? .disabled : controlState + isExpired ? .disabled : globalControlState } } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index a097cded66..0ade3840a2 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -3,6 +3,12 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { typealias Common = InteractionReview struct State: Sendable, Hashable { + let unvalidatedManifest: UnvalidatedTransactionManifest + let nonce: Nonce + let signTransactionPurpose: SigningPurpose.SignTransactionPurpose + let ephemeralNotaryPrivateKey: Curve25519.Signing.PrivateKey = .init() + + var reviewedPreAuthorization: ReviewedPreAuthorization? var dAppName: String? = "CaviarNine" var dAppThumbnail: URL? = .init(string: "https://assets.caviarnine.com/icons/caviarnine_logo_light_400.png") var displayMode: Common.DisplayMode = .detailed @@ -13,8 +19,6 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { // Sections var sections: Common.Sections.State = .init(kind: .preAuthorization) - - init() {} } enum ViewAction: Sendable, Equatable { @@ -29,11 +33,13 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { } enum InternalAction: Sendable, Equatable { + case previewLoaded(TaskResult) case updateSecondsToExpiration(Date) } @Dependency(\.continuousClock) var clock @Dependency(\.pasteboardClient) var pasteboardClient + @Dependency(\.transactionClient) var transactionClient var body: some ReducerOf { Scope(state: \.sections, action: \.child.sections) { @@ -46,11 +52,19 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { switch viewAction { case .appeared: // TODO: Replace mocked data with real logic - let time = Date().addingTimeInterval(90) - state.expiration = .atTime(time) - state.secondsToExpiration = Int(time.timeIntervalSinceNow) - return startTimer(expirationDate: time) - .merge(with: getSections()) + return .run { [state = state] send in + let preview = await TaskResult { + try await transactionClient.getTransactionReview(.init( + unvalidatedManifest: state.unvalidatedManifest, + message: .none, + nonce: state.nonce, + ephemeralNotaryPublicKey: state.ephemeralNotaryPrivateKey.publicKey, + signingPurpose: .signTransaction(state.signTransactionPurpose), // Update + isWalletTransaction: true + )) + } + await send(.internal(.previewLoaded(preview))) + } case .toggleDisplayModeButtonTapped: switch state.displayMode { @@ -73,6 +87,18 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { func reduce(into state: inout State, internalAction: InternalAction) -> Effect { switch internalAction { + case let .previewLoaded(.failure(error)): + // TODO: Handle error + return .none + + case let .previewLoaded(.success(preview)): + state.reviewedPreAuthorization = .init(manifest: preview.transactionManifest) + let time = Date().addingTimeInterval(90) + state.expiration = .atTime(time) + state.secondsToExpiration = Int(time.timeIntervalSinceNow) + return startTimer(expirationDate: time) + .merge(with: getSections(executionSummary: preview.analyzedManifestToReview, networkId: preview.networkID)) + case let .updateSecondsToExpiration(expiration): state.secondsToExpiration = Int(expiration.timeIntervalSinceNow) return .none @@ -81,8 +107,8 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { } private extension PreAuthorizationReview { - func getSections() -> Effect { - .send(.child(.sections(.internal(.parent(.simulate))))) + func getSections(executionSummary: ExecutionSummary, networkId: NetworkID) -> Effect { + .send(.child(.sections(.internal(.parent(.resolveExecutionSummary(executionSummary, networkId)))))) } func startTimer(expirationDate: Date) -> Effect { @@ -95,8 +121,8 @@ private extension PreAuthorizationReview { } } -private extension PreAuthorizationReview { - enum CancellableId: Hashable { +extension PreAuthorizationReview { + private enum CancellableId: Hashable { case expirationTimer } From 90828053f6b837b53d17b90a27e5869d2e5d3645 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Wed, 23 Oct 2024 10:39:42 -0300 Subject: [PATCH 32/63] move tests from Home to DappInteractionFlow --- .../DappInteractionFlow+View.swift | 7 +++++ .../Coordinator/DappInteractionFlow.swift | 28 +++++++++++++------ .../HomeFeature/Coordinator/Home+View.swift | 10 ------- .../HomeFeature/Coordinator/Home.swift | 14 +--------- 4 files changed, 27 insertions(+), 32 deletions(-) diff --git a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow+View.swift b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow+View.swift index a90c0af0a0..382d59613c 100644 --- a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow+View.swift +++ b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow+View.swift @@ -107,6 +107,13 @@ extension DappInteractionFlow { action: DappInteractionFlow.Path.Action.accountsProofOfOwnership, then: { ProofOfOwnership.View(store: $0) } ) + + case .preAuthorizationReview: + CaseLet( + /DappInteractionFlow.Path.MainState.preAuthorizationReview, + action: DappInteractionFlow.Path.Action.preAuthorizationReview, + then: { PreAuthorizationReview.View(store: $0) } + ) } } } diff --git a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift index b36529a7da..e79a674f25 100644 --- a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift +++ b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift @@ -145,6 +145,7 @@ struct DappInteractionFlow: Sendable, FeatureReducer { case reviewTransaction(TransactionReview.State) case personaProofOfOwnership(ProofOfOwnership.State) case accountsProofOfOwnership(ProofOfOwnership.State) + case preAuthorizationReview(PreAuthorizationReview.State) } @CasePathable @@ -157,6 +158,7 @@ struct DappInteractionFlow: Sendable, FeatureReducer { case reviewTransaction(TransactionReview.Action) case personaProofOfOwnership(ProofOfOwnership.Action) case accountsProofOfOwnership(ProofOfOwnership.Action) + case preAuthorizationReview(PreAuthorizationReview.Action) } var body: some ReducerOf { @@ -185,6 +187,9 @@ struct DappInteractionFlow: Sendable, FeatureReducer { Scope(state: \.accountsProofOfOwnership, action: \.accountsProofOfOwnership) { ProofOfOwnership() } + Scope(state: \.preAuthorizationReview, action: \.preAuthorizationReview) { + PreAuthorizationReview() + } } } } @@ -1009,18 +1014,23 @@ extension DappInteractionFlow.Path.State { )) case let .remote(.send(item)): - self.state = .reviewTransaction(.init( + self.state = .preAuthorizationReview(.init( unvalidatedManifest: item.unvalidatedManifest, nonce: .secureRandom(), - signTransactionPurpose: .manifestFromDapp, - message: item.message.map { - Message.plaintext(string: $0) - } ?? Message.none, - waitsForTransactionToBeComitted: interaction.interactionId.isWalletAccountDepositSettingsInteraction, - isWalletTransaction: interaction.interactionId.isWalletInteraction, - proposingDappMetadata: dappMetadata.onLedger, - p2pRoute: p2pRoute + signTransactionPurpose: .manifestFromDapp )) +// self.state = .reviewTransaction(.init( +// unvalidatedManifest: item.unvalidatedManifest, +// nonce: .secureRandom(), +// signTransactionPurpose: .manifestFromDapp, +// message: item.message.map { +// Message.plaintext(string: $0) +// } ?? Message.none, +// waitsForTransactionToBeComitted: interaction.interactionId.isWalletAccountDepositSettingsInteraction, +// isWalletTransaction: interaction.interactionId.isWalletInteraction, +// proposingDappMetadata: dappMetadata.onLedger, +// p2pRoute: p2pRoute +// )) } } } diff --git a/RadixWallet/Features/HomeFeature/Coordinator/Home+View.swift b/RadixWallet/Features/HomeFeature/Coordinator/Home+View.swift index 24fee04bf1..e2bcb2f939 100644 --- a/RadixWallet/Features/HomeFeature/Coordinator/Home+View.swift +++ b/RadixWallet/Features/HomeFeature/Coordinator/Home+View.swift @@ -118,7 +118,6 @@ private extension View { .relinkConnector(with: destinationStore) .securityCenter(with: destinationStore) .p2pLinks(with: destinationStore) - .preAuth(with: destinationStore, store: store) } private func accountDetails(with destinationStore: PresentationStoreOf) -> some View { @@ -160,15 +159,6 @@ private extension View { P2PLinksFeature.View(store: $0) } } - - private func preAuth(with destinationStore: PresentationStoreOf, store: StoreOf) -> some View { - fullScreenCover(store: destinationStore.scope(state: \.preAuth, action: \.preAuth)) { - PreAuthorizationReview.View(store: $0) - .withNavigationBar { - store.send(.view(.dismissPreAuth)) - } - } - } } extension View { diff --git a/RadixWallet/Features/HomeFeature/Coordinator/Home.swift b/RadixWallet/Features/HomeFeature/Coordinator/Home.swift index 5021226d42..9afbe651ed 100644 --- a/RadixWallet/Features/HomeFeature/Coordinator/Home.swift +++ b/RadixWallet/Features/HomeFeature/Coordinator/Home.swift @@ -55,7 +55,6 @@ struct Home: Sendable, FeatureReducer { case createAccountButtonTapped case settingsButtonTapped case showFiatWorthToggled - case dismissPreAuth } enum InternalAction: Sendable, Equatable { @@ -89,7 +88,6 @@ struct Home: Sendable, FeatureReducer { case relinkConnector(NewConnection.State) case securityCenter(SecurityCenter.State) case p2pLinks(P2PLinksFeature.State) - case preAuth(PreAuthorizationReview.State) } @CasePathable @@ -101,7 +99,6 @@ struct Home: Sendable, FeatureReducer { case relinkConnector(NewConnection.Action) case securityCenter(SecurityCenter.Action) case p2pLinks(P2PLinksFeature.Action) - case preAuth(PreAuthorizationReview.Action) enum AcknowledgeJailbreakAlert: Sendable, Hashable {} } @@ -125,9 +122,6 @@ struct Home: Sendable, FeatureReducer { Scope(state: \.p2pLinks, action: \.p2pLinks) { P2PLinksFeature() } - Scope(state: \.preAuth, action: \.preAuth) { - PreAuthorizationReview() - } } } @@ -215,18 +209,12 @@ struct Home: Sendable, FeatureReducer { return fetchAccountPortfolios(state) case .settingsButtonTapped: - state.destination = .preAuth(.init()) - return .none -// return .send(.delegate(.displaySettings)) + return .send(.delegate(.displaySettings)) case .showFiatWorthToggled: return .run { _ in try await appPreferencesClient.toggleIsCurrencyAmountVisible() } - - case .dismissPreAuth: - state.destination = nil - return .none } } From e93cad5ff572bbb0eb25de8afaa2dd0ad88b0576 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Wed, 23 Oct 2024 10:56:27 -0300 Subject: [PATCH 33/63] use real dApp Metadata --- .../Coordinator/DappInteractionFlow.swift | 3 ++- .../PreAuthorizationReview+View.swift | 18 ++++++++++-------- .../PreAuthorizationReview.swift | 15 +++++++++------ 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift index e79a674f25..043428c128 100644 --- a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift +++ b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift @@ -1017,7 +1017,8 @@ extension DappInteractionFlow.Path.State { self.state = .preAuthorizationReview(.init( unvalidatedManifest: item.unvalidatedManifest, nonce: .secureRandom(), - signTransactionPurpose: .manifestFromDapp + signTransactionPurpose: .manifestFromDapp, + dAppMetadata: dappMetadata.onLedger )) // self.state = .reviewTransaction(.init( // unvalidatedManifest: item.unvalidatedManifest, diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index bc9c864c1c..b9867110a6 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -3,8 +3,7 @@ import SwiftUI extension PreAuthorizationReview.State { var viewState: PreAuthorizationReview.ViewState { .init( - dAppName: dAppName, - dAppThumbnail: dAppThumbnail, + dAppMetadata: dAppMetadata, displayMode: displayMode, sliderResetDate: sliderResetDate, expiration: expiration, @@ -18,14 +17,17 @@ extension PreAuthorizationReview.State { // MARK: - PreAuthorizationReview.View extension PreAuthorizationReview { struct ViewState: Equatable { - let dAppName: String? - let dAppThumbnail: URL? + let dAppMetadata: DappMetadata.Ledger? let displayMode: Common.DisplayMode let sliderResetDate: Date let expiration: Expiration? let secondsToExpiration: Int? let globalControlState: ControlState let sliderControlState: ControlState + + var dAppName: String? { + dAppMetadata?.name?.rawValue + } } struct View: SwiftUI.View { @@ -72,7 +74,7 @@ extension PreAuthorizationReview { private func content(_ viewStore: ViewStoreOf) -> some SwiftUI.View { ScrollView(showsIndicators: false) { VStack(spacing: .zero) { - header(dAppName: viewStore.dAppName, dAppThumbnail: viewStore.dAppThumbnail) + header(dAppMetadata: viewStore.dAppMetadata) Group { if let rawContent = viewStore.displayMode.rawTransaction { @@ -114,11 +116,11 @@ extension PreAuthorizationReview { } } - private func header(dAppName: String?, dAppThumbnail: URL?) -> some SwiftUI.View { + private func header(dAppMetadata: DappMetadata.Ledger?) -> some SwiftUI.View { Common.HeaderView( kind: .preAuthorization, - name: dAppName, - thumbnail: dAppThumbnail + name: dAppMetadata?.name?.rawValue, + thumbnail: dAppMetadata?.thumbnail ) .measurePosition(navTitleID, coordSpace: coordSpace) .padding(.horizontal, .medium3) diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 0ade3840a2..f7bcd72685 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -7,14 +7,13 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { let nonce: Nonce let signTransactionPurpose: SigningPurpose.SignTransactionPurpose let ephemeralNotaryPrivateKey: Curve25519.Signing.PrivateKey = .init() + let dAppMetadata: DappMetadata.Ledger? var reviewedPreAuthorization: ReviewedPreAuthorization? - var dAppName: String? = "CaviarNine" - var dAppThumbnail: URL? = .init(string: "https://assets.caviarnine.com/icons/caviarnine_logo_light_400.png") + var expiration: Expiration? + var displayMode: Common.DisplayMode = .detailed var sliderResetDate: Date = .now // TODO: reset when it corresponds - - var expiration: Expiration? var secondsToExpiration: Int? // Sections @@ -40,6 +39,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { @Dependency(\.continuousClock) var clock @Dependency(\.pasteboardClient) var pasteboardClient @Dependency(\.transactionClient) var transactionClient + @Dependency(\.errorQueue) var errorQueue var body: some ReducerOf { Scope(state: \.sections, action: \.child.sections) { @@ -51,7 +51,6 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { func reduce(into state: inout State, viewAction: ViewAction) -> Effect { switch viewAction { case .appeared: - // TODO: Replace mocked data with real logic return .run { [state = state] send in let preview = await TaskResult { try await transactionClient.getTransactionReview(.init( @@ -88,14 +87,18 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { func reduce(into state: inout State, internalAction: InternalAction) -> Effect { switch internalAction { case let .previewLoaded(.failure(error)): - // TODO: Handle error + loggerGlobal.error("PreAuthroization preview failed, error: \(error)") + errorQueue.schedule(error) return .none case let .previewLoaded(.success(preview)): state.reviewedPreAuthorization = .init(manifest: preview.transactionManifest) + + // Mocking expiration until we have Sargon ready. Timer won't be started if expiration != .atTime let time = Date().addingTimeInterval(90) state.expiration = .atTime(time) state.secondsToExpiration = Int(time.timeIntervalSinceNow) + return startTimer(expirationDate: time) .merge(with: getSections(executionSummary: preview.analyzedManifestToReview, networkId: preview.networkID)) From c26ebef514c0445e32d666ed426f349e88964e0e Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Wed, 23 Oct 2024 11:47:21 -0300 Subject: [PATCH 34/63] set up for TransactionSummary --- RadixWallet.xcodeproj/project.pbxproj | 8 ++-- .../Sections/Sections+Simulate.swift | 37 ------------------- .../Sections+TransactionSummary.swift | 10 +++++ .../InteractionReview/Sections/Sections.swift | 8 ++-- .../PreAuthorizationReview.swift | 21 ++++++++--- 5 files changed, 33 insertions(+), 51 deletions(-) delete mode 100644 RadixWallet/Features/InteractionReview/Sections/Sections+Simulate.swift create mode 100644 RadixWallet/Features/InteractionReview/Sections/Sections+TransactionSummary.swift diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index be964b8452..ed73d4e05f 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -731,7 +731,7 @@ 5B27FBFD2CC7E6C1002975BE /* Sections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBFB2CC7E6C1002975BE /* Sections.swift */; }; 5B27FBFE2CC7E6C1002975BE /* Sections+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBFC2CC7E6C1002975BE /* Sections+View.swift */; }; 5B27FC002CC7E783002975BE /* Sections+ExecutionSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBFF2CC7E77B002975BE /* Sections+ExecutionSummary.swift */; }; - 5B27FC022CC7ECC9002975BE /* Sections+Simulate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FC012CC7ECC2002975BE /* Sections+Simulate.swift */; }; + 5B27FC022CC7ECC9002975BE /* Sections+TransactionSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FC012CC7ECC2002975BE /* Sections+TransactionSummary.swift */; }; 5B2A45022BD6680400AEC8AD /* ContactSupportClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */; }; 5B2A45042BD6689100AEC8AD /* ContactSupportClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */; }; 5B3C48A92C7E190C00DB160D /* AssetRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B3C48A82C7E190C00DB160D /* AssetRow.swift */; }; @@ -1968,7 +1968,7 @@ 5B27FBFB2CC7E6C1002975BE /* Sections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sections.swift; sourceTree = ""; }; 5B27FBFC2CC7E6C1002975BE /* Sections+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sections+View.swift"; sourceTree = ""; }; 5B27FBFF2CC7E77B002975BE /* Sections+ExecutionSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sections+ExecutionSummary.swift"; sourceTree = ""; }; - 5B27FC012CC7ECC2002975BE /* Sections+Simulate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sections+Simulate.swift"; sourceTree = ""; }; + 5B27FC012CC7ECC2002975BE /* Sections+TransactionSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sections+TransactionSummary.swift"; sourceTree = ""; }; 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactSupportClient.swift; sourceTree = ""; }; 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactSupportClient+Live.swift"; sourceTree = ""; }; 5B3C48A82C7E190C00DB160D /* AssetRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetRow.swift; sourceTree = ""; }; @@ -5518,7 +5518,7 @@ 5B27FBFC2CC7E6C1002975BE /* Sections+View.swift */, 5B27FBDF2CC6CCBE002975BE /* Sections+Data.swift */, 5B27FBFF2CC7E77B002975BE /* Sections+ExecutionSummary.swift */, - 5B27FC012CC7ECC2002975BE /* Sections+Simulate.swift */, + 5B27FC012CC7ECC2002975BE /* Sections+TransactionSummary.swift */, 48CFBCE42ADC10D800E77A5C /* Accounts */, 48CFBCDE2ADC10D800E77A5C /* Proofs */, 5B27FBF62CC716BC002975BE /* Dapps */, @@ -8223,7 +8223,7 @@ 48AF19CE2BB71C1600796130 /* IntoSargon+Bridge.swift in Sources */, 5B9846C02BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift in Sources */, 48CFC3492ADC10D900E77A5C /* PersonaDataPermissionBox.swift in Sources */, - 5B27FC022CC7ECC9002975BE /* Sections+Simulate.swift in Sources */, + 5B27FC022CC7ECC9002975BE /* Sections+TransactionSummary.swift in Sources */, A408164E2C7E0D08005E65B9 /* TransactionStatus.swift in Sources */, 5BBC43A92BBAC6B0005747B1 /* AppTextEditor.swift in Sources */, A41266F12B15579E00EA38E9 /* ManualAccountRecoverySeedPhrase+View.swift in Sources */, diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+Simulate.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+Simulate.swift deleted file mode 100644 index 8b8b4a1132..0000000000 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+Simulate.swift +++ /dev/null @@ -1,37 +0,0 @@ -extension InteractionReview.Sections { - func simulateSections() async throws -> Common.SectionsData? { - let xrdBalance: ResourceBalance = .init(resource: .init(resourceAddress: .sampleStokenetXRD, metadata: .init(name: "Radix", symbol: "XRD", isComplete: true)), details: .fungible(.init(isXRD: true, amount: .init(nominalAmount: .five)))) - let idResourceBalance = xrdBalance.asIdentified - - let nftBalance: ResourceBalance = .init(resource: .init(resourceAddress: .sampleMainnetNonFungibleGCMembership, atLedgerState: .init(version: 1, epoch: 2), metadata: .init(name: "GC Member Card", iconURL: .init(string: "https://stokenet-gumball-club.radixdlt.com/assets/member-card.png"), isComplete: true)), details: .nonFungible(.init(id: .sample, data: nil))) - - let accountWithdraw = Common.Account.State( - account: .user(.sampleMainnetAlice), - transfers: [idResourceBalance], - isDeposit: false - ) - let withdrawals = Common.Accounts.State( - accounts: [accountWithdraw], - enableCustomizeGuarantees: false - ) - let accountDeposit = Common.Account.State( - account: .user(.sampleMainnetBob), - transfers: [idResourceBalance], - isDeposit: true - ) - let deposits = Common.Accounts.State( - accounts: [accountDeposit], - enableCustomizeGuarantees: false - ) - - let proofs = Common.Proofs.State(kind: .preAuthorization, proofs: [ - .init(resourceBalance: nftBalance), - ]) - - return Common.SectionsData( - withdrawals: withdrawals, - deposits: deposits, - proofs: proofs - ) - } -} diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+TransactionSummary.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+TransactionSummary.swift new file mode 100644 index 0000000000..f9a5cafc87 --- /dev/null +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+TransactionSummary.swift @@ -0,0 +1,10 @@ +extension InteractionReview.Sections { + func sections(for summary: TransactionSummary, networkID: NetworkID) async throws -> Common.SectionsData? { + // TODO: Implement + nil + } +} + +// MARK: - TransactionSummary +// TODO: Delete once we have Sargon model +struct TransactionSummary: Sendable, Equatable {} diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections.swift b/RadixWallet/Features/InteractionReview/Sections/Sections.swift index f241f1001d..32ed27347a 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections.swift @@ -44,7 +44,7 @@ extension InteractionReview { enum ParentAction: Sendable, Equatable { case resolveExecutionSummary(ExecutionSummary, NetworkID) - case simulate + case resolveTransactionSummary(TransactionSummary, NetworkID) case showResourceDetails(OnLedgerEntity.Resource, ResourceBalance.Details) } } @@ -204,12 +204,12 @@ extension InteractionReview { await send(.internal(.setSections(nil))) } - case .simulate: + case let .resolveTransactionSummary(transactionSummary, networkID): .run { send in - let sections = try await simulateSections() + let sections = try await sections(for: transactionSummary, networkID: networkID) await send(.internal(.setSections(sections))) } catch: { error, send in - loggerGlobal.error("Failed to extract sections, error: \(error)") + loggerGlobal.error("Failed to extract sections from TransactionSummary, error: \(error)") await send(.internal(.setSections(nil))) } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index f7bcd72685..36fc2d21f3 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -94,13 +94,26 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { case let .previewLoaded(.success(preview)): state.reviewedPreAuthorization = .init(manifest: preview.transactionManifest) + var effects: [Effect] = [] + let sectionsEffect: Effect + // We will check Preview type to know which type of sections to get + = if 5 > 3 + { + .send(.child(.sections(.internal(.parent(.resolveExecutionSummary( + preview.analyzedManifestToReview, preview.networkID + )))))) + } else { + .send(.child(.sections(.internal(.parent(.resolveTransactionSummary(.init(), preview.networkID)))))) + } + effects.append(sectionsEffect) + // Mocking expiration until we have Sargon ready. Timer won't be started if expiration != .atTime let time = Date().addingTimeInterval(90) state.expiration = .atTime(time) state.secondsToExpiration = Int(time.timeIntervalSinceNow) + effects.append(startTimer(expirationDate: time)) - return startTimer(expirationDate: time) - .merge(with: getSections(executionSummary: preview.analyzedManifestToReview, networkId: preview.networkID)) + return .merge(effects) case let .updateSecondsToExpiration(expiration): state.secondsToExpiration = Int(expiration.timeIntervalSinceNow) @@ -110,10 +123,6 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { } private extension PreAuthorizationReview { - func getSections(executionSummary: ExecutionSummary, networkId: NetworkID) -> Effect { - .send(.child(.sections(.internal(.parent(.resolveExecutionSummary(executionSummary, networkId)))))) - } - func startTimer(expirationDate: Date) -> Effect { .run { send in for await _ in self.clock.timer(interval: .seconds(1)) { From 6ce96057aa7f5a33d89a27334e9d54e8ae938cec Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Fri, 25 Oct 2024 13:37:21 -0300 Subject: [PATCH 35/63] hide raw button until reviewed preAuth available --- .../PreAuthorizationReview+View.swift | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index b9867110a6..8b8b98852e 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -9,7 +9,8 @@ extension PreAuthorizationReview.State { expiration: expiration, secondsToExpiration: secondsToExpiration, globalControlState: globalControlState, - sliderControlState: sliderControlState + sliderControlState: sliderControlState, + showRawTransactionButton: showRawTransactionButton ) } } @@ -24,6 +25,7 @@ extension PreAuthorizationReview { let secondsToExpiration: Int? let globalControlState: ControlState let sliderControlState: ControlState + let showRawTransactionButton: Bool var dAppName: String? { dAppMetadata?.name?.rawValue @@ -80,7 +82,7 @@ extension PreAuthorizationReview { if let rawContent = viewStore.displayMode.rawTransaction { rawTransaction(rawContent) } else { - details + details(viewStore.showRawTransactionButton) } } .background(Common.gradientBackground) @@ -135,17 +137,19 @@ extension PreAuthorizationReview { } } - private var details: some SwiftUI.View { + private func details(_ showRawTransactionButton: Bool) -> some SwiftUI.View { sections .padding(.top, .large2 + .small3) .padding(.horizontal, .small1) .padding(.bottom, .medium1) .overlay(alignment: .topTrailing) { - Button(asset: AssetResource.code) { - store.send(.view(.toggleDisplayModeButtonTapped)) + if showRawTransactionButton { + Button(asset: AssetResource.code) { + store.send(.view(.toggleDisplayModeButtonTapped)) + } + .buttonStyle(.secondaryRectangular) + .padding(.medium3) } - .buttonStyle(.secondaryRectangular) - .padding(.medium3) } } @@ -185,7 +189,7 @@ extension PreAuthorizationReview { let value = formatTime(seconds: seconds) Text("Valid for the next **\(value)**") } else { - Text("This subintent is no longer valid!") + Text("This PreAuthorization is no longer valid") } } @@ -240,4 +244,8 @@ private extension PreAuthorizationReview.State { var sliderControlState: ControlState { isExpired ? .disabled : globalControlState } + + var showRawTransactionButton: Bool { + globalControlState == .enabled + } } From 4ef9e884ec6cb08a1a38c8ad63ce9e3f3aa6a2e0 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Fri, 25 Oct 2024 14:54:44 -0300 Subject: [PATCH 36/63] fix HeadingView to always have the same frame --- .../Features/InteractionReview/Components/HeadingView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/RadixWallet/Features/InteractionReview/Components/HeadingView.swift b/RadixWallet/Features/InteractionReview/Components/HeadingView.swift index 0b717a51fc..af6916236f 100644 --- a/RadixWallet/Features/InteractionReview/Components/HeadingView.swift +++ b/RadixWallet/Features/InteractionReview/Components/HeadingView.swift @@ -13,6 +13,7 @@ extension InteractionReview { var body: some View { HStack(spacing: .small2) { Image(asset: icon) + .frame(.smallest) .padding(.small3) .overlay { Circle() From 38f4fd12e384dd1f79b7b8b62398d5c630bba9ad Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Fri, 25 Oct 2024 15:21:18 -0300 Subject: [PATCH 37/63] possible dApp calls --- .../Sections/Sections+View.swift | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift index 686f335fa4..a399455173 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift @@ -8,6 +8,7 @@ extension InteractionReview.Sections.State { isExpandedRedeemingFromPools: redeemingFromPools?.isExpanded == true, showTransferLine: withdrawals != nil && deposits != nil, showProofs: kind == .preAuthorization, + showPossibleDappCalls: showPossibleDappCalls, stakingToValidators: stakingToValidators, unstakingFromValidators: unstakingFromValidators, claimingFromValidators: claimingFromValidators, @@ -25,6 +26,7 @@ extension InteractionReview.Sections { let isExpandedRedeemingFromPools: Bool let showTransferLine: Bool let showProofs: Bool + let showPossibleDappCalls: Bool let stakingToValidators: InteractionReview.ValidatorsState? let unstakingFromValidators: InteractionReview.ValidatorsState? @@ -53,7 +55,7 @@ extension InteractionReview.Sections { unstakingFromValidators(viewStore.unstakingFromValidators) claimingFromValidators(viewStore.claimingFromValidators) - dAppsUsed(viewStore.isExpandedDappsUsed) + dAppsUsed(viewStore.isExpandedDappsUsed, showPossibleDappCalls: viewStore.showPossibleDappCalls) deposits @@ -169,7 +171,7 @@ extension InteractionReview.Sections { } @ViewBuilder - private func dAppsUsed(_ isExpanded: Bool) -> some SwiftUI.View { + private func dAppsUsed(_ isExpanded: Bool, showPossibleDappCalls: Bool) -> some SwiftUI.View { IfLetStore(store.scope(state: \.dAppsUsed, action: \.child.dAppsUsed)) { childStore in VStack(alignment: .leading, spacing: .small2) { Common.ExpandableHeadingView(heading: .usingDapps, isExpanded: isExpanded) { @@ -179,10 +181,38 @@ extension InteractionReview.Sections { InteractionReviewDappsUsed.View(store: childStore) .transition(.opacity.combined(with: .scale(scale: 0.95))) } + if showPossibleDappCalls { + possibleDappCalls + } } } } + private var possibleDappCalls: some SwiftUI.View { + HStack(spacing: .zero) { + Image(.transactionReviewDapps) + .renderingMode(.template) + .resizable() + .foregroundStyle(.app.gray3) + .frame(.smallest) + + Text("Possible dApp calls") + .textStyle(.body2HighImportance) + .foregroundStyle(.app.gray2) + .padding(.leading, .small2) + + Spacer() + + InfoButton(.dapps) + } + .padding(.leading, .medium3) + .padding(.vertical, .small1) + .padding(.trailing, .medium2) + .background(.app.white) + .clipShape(RoundedRectangle(cornerRadius: .small1)) + .cardShadow + } + @ViewBuilder private var deposits: some SwiftUI.View { IfLetStore(store.scope(state: \.deposits, action: \.child.deposits)) { childStore in @@ -207,6 +237,16 @@ extension InteractionReview.Sections.State { var showTransferLine: Bool { withdrawals != nil && deposits != nil } + + var showPossibleDappCalls: Bool { + switch kind { + case .transaction: + false + case .preAuthorization: + // TODO: Only show for open pre authorizations + true + } + } } extension StoreOf { From 617c6ebf7dcdf8722a5c9c3d215d404cc4da6a1b Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Fri, 25 Oct 2024 15:41:11 -0300 Subject: [PATCH 38/63] add InfoLink support --- .../Features/AppFeature/Overlay/InfoLinkSheet+Reducer.swift | 6 ++++++ .../Features/InteractionReview/Sections/Sections+View.swift | 2 +- .../PreAuthorizationReview+View.swift | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/RadixWallet/Features/AppFeature/Overlay/InfoLinkSheet+Reducer.swift b/RadixWallet/Features/AppFeature/Overlay/InfoLinkSheet+Reducer.swift index 6785aa145c..9afb6c6e54 100644 --- a/RadixWallet/Features/AppFeature/Overlay/InfoLinkSheet+Reducer.swift +++ b/RadixWallet/Features/AppFeature/Overlay/InfoLinkSheet+Reducer.swift @@ -58,6 +58,8 @@ extension InfoLinkSheet { case dashboard case bridging case payingaccount + case preauthorizations + case possibledappcalls } } @@ -153,6 +155,10 @@ extension InfoLinkSheet.GlossaryItem { L10n.InfoLink.Glossary.bridging case .payingaccount: L10n.InfoLink.Glossary.payingaccount + case .preauthorizations: + L10n.InfoLink.Glossary.preauthorizations + case .possibledappcalls: + L10n.InfoLink.Glossary.possibledappcalls } } } diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift index a399455173..71f88c56ff 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift @@ -203,7 +203,7 @@ extension InteractionReview.Sections { Spacer() - InfoButton(.dapps) + InfoButton(.possibledappcalls) } .padding(.leading, .medium3) .padding(.vertical, .small1) diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index 8b8b98852e..6ae2f4d596 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -171,7 +171,7 @@ extension PreAuthorizationReview { Spacer(minLength: .small2) - InfoButton(.dapps) // TODO: Update to correct one + InfoButton(.preauthorizations) } .padding(.vertical, .medium3) .padding(.horizontal, .medium2) From 2af392c534f64b1c86a7d473b02d9f3da43534e4 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Fri, 25 Oct 2024 15:50:33 -0300 Subject: [PATCH 39/63] set lineSpacing of feesInfo --- .../PreAuthorizationReview/PreAuthorizationReview+View.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index 6ae2f4d596..0fdafb5181 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -167,6 +167,7 @@ extension PreAuthorizationReview { Text("Network fees will be paid by the dApp") .foregroundStyle(.app.gray2) } + .lineSpacing(0) .textStyle(.body2Regular) Spacer(minLength: .small2) From f594f53585c58c8957fa40623e305d2d3b962d20 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Fri, 25 Oct 2024 09:45:39 -0300 Subject: [PATCH 40/63] handle preAuhtorization request --- .../Coordinator/DappInteractionFlow.swift | 26 ++++++++++--------- .../Coordinator/DappInteractionModels.swift | 12 +++++++-- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift index 3b31cf4ff0..62c8b42aa0 100644 --- a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift +++ b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift @@ -1014,24 +1014,26 @@ extension DappInteractionFlow.Path.State { )) case let .remote(.send(item)): + self.state = .reviewTransaction(.init( + unvalidatedManifest: item.unvalidatedManifest, + nonce: .secureRandom(), + signTransactionPurpose: .manifestFromDapp, + message: item.message.map { + Message.plaintext(string: $0) + } ?? Message.none, + waitsForTransactionToBeComitted: interaction.interactionId.isWalletAccountDepositSettingsInteraction, + isWalletTransaction: interaction.interactionId.isWalletInteraction, + proposingDappMetadata: dappMetadata.onLedger, + p2pRoute: p2pRoute + )) + + case let .remote(.subintent(item)): self.state = .preAuthorizationReview(.init( unvalidatedManifest: item.unvalidatedManifest, nonce: .secureRandom(), signTransactionPurpose: .manifestFromDapp, dAppMetadata: dappMetadata.onLedger )) -// self.state = .reviewTransaction(.init( -// unvalidatedManifest: item.unvalidatedManifest, -// nonce: .secureRandom(), -// signTransactionPurpose: .manifestFromDapp, -// message: item.message.map { -// Message.plaintext(string: $0) -// } ?? Message.none, -// waitsForTransactionToBeComitted: interaction.interactionId.isWalletAccountDepositSettingsInteraction, -// isWalletTransaction: interaction.interactionId.isWalletInteraction, -// proposingDappMetadata: dappMetadata.onLedger, -// p2pRoute: p2pRoute -// )) } } } diff --git a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionModels.swift b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionModels.swift index 171d2970fe..9292dce1e1 100644 --- a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionModels.swift +++ b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionModels.swift @@ -111,6 +111,9 @@ extension DappToWalletInteraction { // transactions case send(DappToWalletInteractionSendTransactionItem) + // preAuthorization + case subintent(DappToWalletInteractionSubintentRequestItem) + var priority: some Comparable { switch self { // requests @@ -131,6 +134,9 @@ extension DappToWalletInteraction { // transactions case .send: 0 + // preAuthorization + case .subintent: + 0 } } } @@ -162,8 +168,10 @@ extension DappToWalletInteraction { .send(items.send), ] .compactMap { $0 } - case .preAuthorization: - fatalError("TODO implement") + case let .preAuthorization(items): + [ + .subintent(items.request), + ] } } } From 4ab916dd27c67273b1530bff2545f054d5c85e89 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 28 Oct 2024 15:12:12 -0300 Subject: [PATCH 41/63] temporary fix until Strings merged --- .../Features/AppFeature/Overlay/InfoLinkSheet+Reducer.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RadixWallet/Features/AppFeature/Overlay/InfoLinkSheet+Reducer.swift b/RadixWallet/Features/AppFeature/Overlay/InfoLinkSheet+Reducer.swift index 9afb6c6e54..55a63a1497 100644 --- a/RadixWallet/Features/AppFeature/Overlay/InfoLinkSheet+Reducer.swift +++ b/RadixWallet/Features/AppFeature/Overlay/InfoLinkSheet+Reducer.swift @@ -156,9 +156,9 @@ extension InfoLinkSheet.GlossaryItem { case .payingaccount: L10n.InfoLink.Glossary.payingaccount case .preauthorizations: - L10n.InfoLink.Glossary.preauthorizations + "L10n.InfoLink.Glossary.preauthorizations" case .possibledappcalls: - L10n.InfoLink.Glossary.possibledappcalls + "L10n.InfoLink.Glossary.possibledappcalls" } } } From 090143039ad9e6d4833f32a3b7a2d332458805cd Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 28 Oct 2024 15:20:42 -0300 Subject: [PATCH 42/63] local Sargon --- RadixWallet.xcodeproj/project.pbxproj | 19 +++++++++---------- .../xcshareddata/swiftpm/Package.resolved | 11 +---------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index b619a99526..200938f2e5 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 56; + objectVersion = 60; objects = { /* Begin PBXBuildFile section */ @@ -7089,7 +7089,7 @@ 8318BB172BC8403800057BCB /* XCRemoteSwiftPackageReference "swift-custom-dump" */, E6A0B0492BF23C7000617DAC /* XCRemoteSwiftPackageReference "swift-identified-collections" */, 5B634A922C91D2A0004B2FBC /* XCRemoteSwiftPackageReference "ScreenshotPreventing-iOS" */, - 835BA27A2CAB1FB100407AE9 /* XCRemoteSwiftPackageReference "sargon" */, + 5B84339D2CD00D6B00CA00F5 /* XCLocalSwiftPackageReference "../sargon" */, ); productRefGroup = 48CFBC502ADC106300E77A5C /* Products */; projectDirPath = ""; @@ -8913,6 +8913,13 @@ }; /* End XCConfigurationList section */ +/* Begin XCLocalSwiftPackageReference section */ + 5B84339D2CD00D6B00CA00F5 /* XCLocalSwiftPackageReference "../sargon" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = ../sargon; + }; +/* End XCLocalSwiftPackageReference section */ + /* Begin XCRemoteSwiftPackageReference section */ 48FFFA972ADC1EEC00B2B213 /* XCRemoteSwiftPackageReference "AsyncExtensions" */ = { isa = XCRemoteSwiftPackageReference; @@ -9170,14 +9177,6 @@ version = 1.3.0; }; }; - 835BA27A2CAB1FB100407AE9 /* XCRemoteSwiftPackageReference "sargon" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/radixdlt/sargon"; - requirement = { - kind = exactVersion; - version = 1.1.34; - }; - }; A415574E2B757C5E0040AD4E /* XCRemoteSwiftPackageReference "swift-composable-architecture" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/pointfreeco/swift-composable-architecture"; diff --git a/RadixWallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/RadixWallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 245640844e..a4f2980f58 100644 --- a/RadixWallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/RadixWallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "7d3590b225945abb1bc0ab6c684b005c28c64bdc204afcc2d34c3e379ef8a3c8", + "originHash" : "7f60b9440372970c3babd29a9b932ebc8ecfa0ac5354d2e8f481e93f420caa72", "pins" : [ { "identity" : "anycodable", @@ -109,15 +109,6 @@ "version" : "11.6.4" } }, - { - "identity" : "sargon", - "kind" : "remoteSourceControl", - "location" : "https://github.com/radixdlt/sargon", - "state" : { - "revision" : "e065e142c589fe89a8123b0345c185c79656c2ec", - "version" : "1.1.34" - } - }, { "identity" : "screenshotpreventing-ios", "kind" : "remoteSourceControl", From 8c8e5ecb65f58789593134a837c1a15dc39c2aad Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 28 Oct 2024 16:39:44 -0300 Subject: [PATCH 43/63] use real models --- RadixWallet.xcodeproj/project.pbxproj | 44 ++++++- .../Models/PreAuthorizationFailure.swift | 27 +++++ .../Models/PreAuthorizationModels.swift | 15 +++ .../PreAuthorizationClient+Interface.swift | 17 +++ .../PreAuthorizationClient+Live.swift | 32 +++++ .../PreAuthorizationClient+Test.swift | 19 +++ .../TransactionClient+Live.swift | 1 - .../Coordinator/DappInteractionFlow.swift | 1 + .../Sections/Sections+ManifestSummary.swift | 6 + .../Sections+TransactionSummary.swift | 10 -- .../InteractionReview/Sections/Sections.swift | 8 +- .../PreAuthorizationReview+View.swift | 4 +- .../PreAuthorizationReview.swift | 110 +++++++----------- 13 files changed, 203 insertions(+), 91 deletions(-) create mode 100644 RadixWallet/Clients/PreAuthorizationClient/Models/PreAuthorizationFailure.swift create mode 100644 RadixWallet/Clients/PreAuthorizationClient/Models/PreAuthorizationModels.swift create mode 100644 RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Interface.swift create mode 100644 RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Live.swift create mode 100644 RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Test.swift create mode 100644 RadixWallet/Features/InteractionReview/Sections/Sections+ManifestSummary.swift delete mode 100644 RadixWallet/Features/InteractionReview/Sections/Sections+TransactionSummary.swift diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index 200938f2e5..c30cf46ce2 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -731,7 +731,7 @@ 5B27FBFD2CC7E6C1002975BE /* Sections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBFB2CC7E6C1002975BE /* Sections.swift */; }; 5B27FBFE2CC7E6C1002975BE /* Sections+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBFC2CC7E6C1002975BE /* Sections+View.swift */; }; 5B27FC002CC7E783002975BE /* Sections+ExecutionSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FBFF2CC7E77B002975BE /* Sections+ExecutionSummary.swift */; }; - 5B27FC022CC7ECC9002975BE /* Sections+TransactionSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FC012CC7ECC2002975BE /* Sections+TransactionSummary.swift */; }; + 5B27FC022CC7ECC9002975BE /* Sections+ManifestSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B27FC012CC7ECC2002975BE /* Sections+ManifestSummary.swift */; }; 5B2A45022BD6680400AEC8AD /* ContactSupportClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */; }; 5B2A45042BD6689100AEC8AD /* ContactSupportClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */; }; 5B3C48A92C7E190C00DB160D /* AssetRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B3C48A82C7E190C00DB160D /* AssetRow.swift */; }; @@ -780,6 +780,11 @@ 5B80FCC42C298E68008444F5 /* ArbitraryDataFieldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B80FCC32C298E68008444F5 /* ArbitraryDataFieldView.swift */; }; 5B80FCC72C298F13008444F5 /* ArbitraryDataField+Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B80FCC62C298F13008444F5 /* ArbitraryDataField+Models.swift */; }; 5B80FCC92C299159008444F5 /* ArbitraryDataField+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B80FCC82C299159008444F5 /* ArbitraryDataField+Helpers.swift */; }; + 5B8433A12CD010DD00CA00F5 /* PreAuthorizationClient+Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8433A02CD010DD00CA00F5 /* PreAuthorizationClient+Interface.swift */; }; + 5B8433A42CD011B600CA00F5 /* PreAuthorizationModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8433A32CD011B000CA00F5 /* PreAuthorizationModels.swift */; }; + 5B8433A62CD011DE00CA00F5 /* PreAuthorizationClient+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8433A52CD011DC00CA00F5 /* PreAuthorizationClient+Test.swift */; }; + 5B8433A82CD0128000CA00F5 /* PreAuthorizationClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8433A72CD0127900CA00F5 /* PreAuthorizationClient+Live.swift */; }; + 5B8433AA2CD0131B00CA00F5 /* PreAuthorizationFailure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8433A92CD0131500CA00F5 /* PreAuthorizationFailure.swift */; }; 5B96DD372BD917B300722882 /* Text+Extra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B96DD362BD917B300722882 /* Text+Extra.swift */; }; 5B9846BD2BBD5C8800E814F3 /* SensitiveInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5B9846BC2BBD5C8800E814F3 /* SensitiveInfo.plist */; }; 5B9846C02BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9846BF2BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift */; }; @@ -1968,7 +1973,7 @@ 5B27FBFB2CC7E6C1002975BE /* Sections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sections.swift; sourceTree = ""; }; 5B27FBFC2CC7E6C1002975BE /* Sections+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sections+View.swift"; sourceTree = ""; }; 5B27FBFF2CC7E77B002975BE /* Sections+ExecutionSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sections+ExecutionSummary.swift"; sourceTree = ""; }; - 5B27FC012CC7ECC2002975BE /* Sections+TransactionSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sections+TransactionSummary.swift"; sourceTree = ""; }; + 5B27FC012CC7ECC2002975BE /* Sections+ManifestSummary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sections+ManifestSummary.swift"; sourceTree = ""; }; 5B2A45012BD6680400AEC8AD /* ContactSupportClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactSupportClient.swift; sourceTree = ""; }; 5B2A45032BD6689100AEC8AD /* ContactSupportClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactSupportClient+Live.swift"; sourceTree = ""; }; 5B3C48A82C7E190C00DB160D /* AssetRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetRow.swift; sourceTree = ""; }; @@ -2014,6 +2019,11 @@ 5B80FCC32C298E68008444F5 /* ArbitraryDataFieldView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArbitraryDataFieldView.swift; sourceTree = ""; }; 5B80FCC62C298F13008444F5 /* ArbitraryDataField+Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ArbitraryDataField+Models.swift"; sourceTree = ""; }; 5B80FCC82C299159008444F5 /* ArbitraryDataField+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ArbitraryDataField+Helpers.swift"; sourceTree = ""; }; + 5B8433A02CD010DD00CA00F5 /* PreAuthorizationClient+Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationClient+Interface.swift"; sourceTree = ""; }; + 5B8433A32CD011B000CA00F5 /* PreAuthorizationModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreAuthorizationModels.swift; sourceTree = ""; }; + 5B8433A52CD011DC00CA00F5 /* PreAuthorizationClient+Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationClient+Test.swift"; sourceTree = ""; }; + 5B8433A72CD0127900CA00F5 /* PreAuthorizationClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationClient+Live.swift"; sourceTree = ""; }; + 5B8433A92CD0131500CA00F5 /* PreAuthorizationFailure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreAuthorizationFailure.swift; sourceTree = ""; }; 5B96DD362BD917B300722882 /* Text+Extra.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Text+Extra.swift"; sourceTree = ""; }; 5B9846BC2BBD5C8800E814F3 /* SensitiveInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = SensitiveInfo.plist; sourceTree = ""; }; 5B9846BF2BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SensitiveInfoClient+Interface.swift"; sourceTree = ""; }; @@ -4480,6 +4490,7 @@ 48CFC0D02ADC10D900E77A5C /* SubmitTransactionClient */, 83823EA82B72362600827211 /* TokenPriceClient */, 48CFBF822ADC10D900E77A5C /* TransactionClient */, + 5B84339F2CD010AD00CA00F5 /* PreAuthorizationClient */, A462B5752B820D1200C26D20 /* TransactionHistoryClient */, 48CFBFAE2ADC10D900E77A5C /* TransportProfileClient */, 48CFC0C52ADC10D900E77A5C /* URLFormatterClient */, @@ -5518,7 +5529,7 @@ 5B27FBFC2CC7E6C1002975BE /* Sections+View.swift */, 5B27FBDF2CC6CCBE002975BE /* Sections+Data.swift */, 5B27FBFF2CC7E77B002975BE /* Sections+ExecutionSummary.swift */, - 5B27FC012CC7ECC2002975BE /* Sections+TransactionSummary.swift */, + 5B27FC012CC7ECC2002975BE /* Sections+ManifestSummary.swift */, 48CFBCE42ADC10D800E77A5C /* Accounts */, 48CFBCDE2ADC10D800E77A5C /* Proofs */, 5B27FBF62CC716BC002975BE /* Dapps */, @@ -5728,6 +5739,26 @@ path = ArbitraryDataField; sourceTree = ""; }; + 5B84339F2CD010AD00CA00F5 /* PreAuthorizationClient */ = { + isa = PBXGroup; + children = ( + 5B8433A72CD0127900CA00F5 /* PreAuthorizationClient+Live.swift */, + 5B8433A02CD010DD00CA00F5 /* PreAuthorizationClient+Interface.swift */, + 5B8433A52CD011DC00CA00F5 /* PreAuthorizationClient+Test.swift */, + 5B8433A22CD011A200CA00F5 /* Models */, + ); + path = PreAuthorizationClient; + sourceTree = ""; + }; + 5B8433A22CD011A200CA00F5 /* Models */ = { + isa = PBXGroup; + children = ( + 5B8433A92CD0131500CA00F5 /* PreAuthorizationFailure.swift */, + 5B8433A32CD011B000CA00F5 /* PreAuthorizationModels.swift */, + ); + path = Models; + sourceTree = ""; + }; 5B9846BE2BBD5EF600E814F3 /* SensitiveInfoClient */ = { isa = PBXGroup; children = ( @@ -7354,6 +7385,7 @@ 48CFC3092ADC10D900E77A5C /* DisplayMnemonics.swift in Sources */, 48CFC24D2ADC10D900E77A5C /* GatewayList+Reducer.swift in Sources */, 48CFC2C42ADC10D900E77A5C /* AssetTransferMessage+View.swift in Sources */, + 5B8433A62CD011DE00CA00F5 /* PreAuthorizationClient+Test.swift in Sources */, 48CFC5FD2ADC10DA00E77A5C /* HTTPURLSessionResponse.swift in Sources */, 83856D622B0279080026452A /* VerifyMnemonic+View.swift in Sources */, A408163A2C7E0D08005E65B9 /* StreamTransactionsResponse.swift in Sources */, @@ -7407,6 +7439,7 @@ 5B27FC002CC7E783002975BE /* Sections+ExecutionSummary.swift in Sources */, 48CFC43E2ADC10DA00E77A5C /* FactorSourcesClient+Interface.swift in Sources */, 48CFC4062ADC10DA00E77A5C /* JSONValue.swift in Sources */, + 5B8433A12CD010DD00CA00F5 /* PreAuthorizationClient+Interface.swift in Sources */, 48CFC5812ADC10DA00E77A5C /* URLFormatterClient+Test.swift in Sources */, 48CFC4112ADC10DA00E77A5C /* ErrorQueue+Live.swift in Sources */, 48CFC48D2ADC10DA00E77A5C /* DiskPersistenceClient+Live.swift in Sources */, @@ -7862,6 +7895,7 @@ 484161472BCAD2D700D2B644 /* Stage1MigrateToSargon+HierarchicalDeterministicPublicKey.swift in Sources */, 48CFC3762ADC10D900E77A5C /* ValidatorStakeView.swift in Sources */, 48CFC4612ADC10DA00E77A5C /* MakeTransactionHeaderInput.swift in Sources */, + 5B8433AA2CD0131B00CA00F5 /* PreAuthorizationFailure.swift in Sources */, A40815C62C7E0D08005E65B9 /* NonFungibleResourcesCollectionItemVaultAggregatedVault.swift in Sources */, 5B4E1D132CB421EB002FAC2E /* DepositStatus.swift in Sources */, 48CFC2F22ADC10D900E77A5C /* CreatePersonaCoordinator+View.swift in Sources */, @@ -7878,6 +7912,7 @@ 48CFC3112ADC10D900E77A5C /* AccountsToImport+View.swift in Sources */, 48CFC5A12ADC10DA00E77A5C /* Stroke.swift in Sources */, 48CFC3812ADC10D900E77A5C /* NFTHelperViews.swift in Sources */, + 5B8433A42CD011B600CA00F5 /* PreAuthorizationModels.swift in Sources */, 48CFC61B2ADC10DA00E77A5C /* P2P+RTCOutgoingMessage.swift in Sources */, 48CFC5BF2ADC10DA00E77A5C /* LoadingOverlayView.swift in Sources */, 48CFC3FD2ADC10D900E77A5C /* RTCPeerConnection+PeerConnection.swift in Sources */, @@ -8223,7 +8258,7 @@ 48AF19CE2BB71C1600796130 /* IntoSargon+Bridge.swift in Sources */, 5B9846C02BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift in Sources */, 48CFC3492ADC10D900E77A5C /* PersonaDataPermissionBox.swift in Sources */, - 5B27FC022CC7ECC9002975BE /* Sections+TransactionSummary.swift in Sources */, + 5B27FC022CC7ECC9002975BE /* Sections+ManifestSummary.swift in Sources */, A408164E2C7E0D08005E65B9 /* TransactionStatus.swift in Sources */, 5BBC43A92BBAC6B0005747B1 /* AppTextEditor.swift in Sources */, A41266F12B15579E00EA38E9 /* ManualAccountRecoverySeedPhrase+View.swift in Sources */, @@ -8304,6 +8339,7 @@ 48CFC5BE2ADC10DA00E77A5C /* RoundedCornerBackground.swift in Sources */, A4F30C942C7CA71400F983D6 /* WithNavigationBar.swift in Sources */, 48AE39DD2B0CBE3900813CF3 /* AccountRecoveryScanCoordinator+View.swift in Sources */, + 5B8433A82CD0128000CA00F5 /* PreAuthorizationClient+Live.swift in Sources */, 48CFC2FA2ADC10D900E77A5C /* NewPersonaCompletion+View.swift in Sources */, 48CFC3702ADC10D900E77A5C /* FungibleAssetList+Reducer.swift in Sources */, 83EE48DE2B8F4081006CE672 /* AccountPortfoliosClient+State.swift in Sources */, diff --git a/RadixWallet/Clients/PreAuthorizationClient/Models/PreAuthorizationFailure.swift b/RadixWallet/Clients/PreAuthorizationClient/Models/PreAuthorizationFailure.swift new file mode 100644 index 0000000000..49da0a8475 --- /dev/null +++ b/RadixWallet/Clients/PreAuthorizationClient/Models/PreAuthorizationFailure.swift @@ -0,0 +1,27 @@ +import Foundation + +// MARK: - PreAuthorizationFailure +enum PreAuthorizationFailure: Sendable, LocalizedError, Equatable { + case failedToGetPreview(FailedToGetPreview) + + var errorDescription: String? { + switch self { + case let .failedToGetPreview(error): + error.localizedDescription + } + } +} + +// MARK: PreAuthorizationFailure.FailedToGetPreview +extension PreAuthorizationFailure { + enum FailedToGetPreview: Sendable, LocalizedError, Equatable { + case failedToAnalyse(Error) + + var errorDescription: String? { + switch self { + case let .failedToAnalyse(error): + "Failed to analyse PreAuthorization Preview: \(error.localizedDescription)" + } + } + } +} diff --git a/RadixWallet/Clients/PreAuthorizationClient/Models/PreAuthorizationModels.swift b/RadixWallet/Clients/PreAuthorizationClient/Models/PreAuthorizationModels.swift new file mode 100644 index 0000000000..6648243cac --- /dev/null +++ b/RadixWallet/Clients/PreAuthorizationClient/Models/PreAuthorizationModels.swift @@ -0,0 +1,15 @@ +import Foundation + +struct PreAuthorizationToReview: Sendable, Hashable { + let kind: PreAuthToReview + let networkID: NetworkID + + var manifest: SubintentManifest { + switch kind { + case let .open(open): + open.manifest + case let .enclosed(enclosed): + enclosed.manifest + } + } +} diff --git a/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Interface.swift b/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Interface.swift new file mode 100644 index 0000000000..3bdb61a459 --- /dev/null +++ b/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Interface.swift @@ -0,0 +1,17 @@ +// MARK: - PreAuthorizationClient +struct PreAuthorizationClient: Sendable { + var getPreview: GetPreview +} + +// MARK: PreAuthorizationClient.GetPreview +extension PreAuthorizationClient { + typealias GetPreview = @Sendable (GetPreviewRequest) async throws -> PreAuthorizationToReview +} + +// MARK: PreAuthorizationClient.GetPreviewRequest +extension PreAuthorizationClient { + struct GetPreviewRequest: Hashable, Sendable { + let unvalidatedManifest: UnvalidatedTransactionManifest + let nonce: Nonce + } +} diff --git a/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Live.swift b/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Live.swift new file mode 100644 index 0000000000..8428cf913c --- /dev/null +++ b/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Live.swift @@ -0,0 +1,32 @@ +extension PreAuthorizationClient: DependencyKey { + static var liveValue: Self { + @Dependency(\.gatewaysClient) var gatewaysClient + + @Sendable + func analysePreview(request: GetPreviewRequest) async throws -> PreAuthToReview { + do { + return try await SargonOS.shared.analysePreAuthPreview( + instructions: request.unvalidatedManifest.transactionManifestString, + blobs: request.unvalidatedManifest.blobs, + nonce: request.nonce + ) + } catch { + throw PreAuthorizationFailure.failedToGetPreview(.failedToAnalyse(error)) + } + } + + let getPreview: GetPreview = { request in + let kind = try await analysePreview(request: request) + let networkID = await gatewaysClient.getCurrentNetworkID() + + return PreAuthorizationToReview( + kind: kind, + networkID: networkID + ) + } + + return Self( + getPreview: getPreview + ) + } +} diff --git a/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Test.swift b/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Test.swift new file mode 100644 index 0000000000..7795cd0b38 --- /dev/null +++ b/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Test.swift @@ -0,0 +1,19 @@ +extension DependencyValues { + var preAuthorizationClient: PreAuthorizationClient { + get { self[PreAuthorizationClient.self] } + set { self[PreAuthorizationClient.self] = newValue } + } +} + +// MARK: - PreAuthorizationClient + TestDependencyKey +extension PreAuthorizationClient: TestDependencyKey { + static let previewValue = Self.noop + + static let noop = Self( + getPreview: { _ in throw NoopError() } + ) + + static let testValue = Self( + getPreview: unimplemented("\(Self.self).getPreview") + ) +} diff --git a/RadixWallet/Clients/TransactionClient/TransactionClient+Live.swift b/RadixWallet/Clients/TransactionClient/TransactionClient+Live.swift index 31b49cff97..1dab056874 100644 --- a/RadixWallet/Clients/TransactionClient/TransactionClient+Live.swift +++ b/RadixWallet/Clients/TransactionClient/TransactionClient+Live.swift @@ -161,7 +161,6 @@ extension TransactionClient { return try await SargonOS.shared.analyseTransactionPreview( instructions: request.unvalidatedManifest.transactionManifestString, blobs: request.unvalidatedManifest.blobs, - message: request.message, areInstructionsOriginatingFromHost: request.isWalletTransaction, nonce: request.nonce, notaryPublicKey: .ed25519(request.ephemeralNotaryPublicKey.intoSargon()) diff --git a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift index 62c8b42aa0..5cfd960e7d 100644 --- a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift +++ b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift @@ -1030,6 +1030,7 @@ extension DappInteractionFlow.Path.State { case let .remote(.subintent(item)): self.state = .preAuthorizationReview(.init( unvalidatedManifest: item.unvalidatedManifest, + expiration: item.expiration, nonce: .secureRandom(), signTransactionPurpose: .manifestFromDapp, dAppMetadata: dappMetadata.onLedger diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+ManifestSummary.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+ManifestSummary.swift new file mode 100644 index 0000000000..06e43895b6 --- /dev/null +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+ManifestSummary.swift @@ -0,0 +1,6 @@ +extension InteractionReview.Sections { + func sections(for summary: ManifestSummary, networkID: NetworkID) async throws -> Common.SectionsData? { + // TODO: Implement + nil + } +} diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+TransactionSummary.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+TransactionSummary.swift deleted file mode 100644 index f9a5cafc87..0000000000 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+TransactionSummary.swift +++ /dev/null @@ -1,10 +0,0 @@ -extension InteractionReview.Sections { - func sections(for summary: TransactionSummary, networkID: NetworkID) async throws -> Common.SectionsData? { - // TODO: Implement - nil - } -} - -// MARK: - TransactionSummary -// TODO: Delete once we have Sargon model -struct TransactionSummary: Sendable, Equatable {} diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections.swift b/RadixWallet/Features/InteractionReview/Sections/Sections.swift index 32ed27347a..37152f79c7 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections.swift @@ -44,7 +44,7 @@ extension InteractionReview { enum ParentAction: Sendable, Equatable { case resolveExecutionSummary(ExecutionSummary, NetworkID) - case resolveTransactionSummary(TransactionSummary, NetworkID) + case resolveManifestSummary(ManifestSummary, NetworkID) case showResourceDetails(OnLedgerEntity.Resource, ResourceBalance.Details) } } @@ -204,12 +204,12 @@ extension InteractionReview { await send(.internal(.setSections(nil))) } - case let .resolveTransactionSummary(transactionSummary, networkID): + case let .resolveManifestSummary(manifestSummary, networkID): .run { send in - let sections = try await sections(for: transactionSummary, networkID: networkID) + let sections = try await sections(for: manifestSummary, networkID: networkID) await send(.internal(.setSections(sections))) } catch: { error, send in - loggerGlobal.error("Failed to extract sections from TransactionSummary, error: \(error)") + loggerGlobal.error("Failed to extract sections from ManifestSummary, error: \(error)") await send(.internal(.setSections(nil))) } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index 0fdafb5181..ea766d2653 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -194,8 +194,8 @@ extension PreAuthorizationReview { } } - case let .window(seconds): - let value = formatTime(seconds: seconds) + case let .afterDelay(value): + let value = formatTime(seconds: Int(value.expireAfterSeconds)) Text("Valid for **\(value) after approval**") case nil: diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 36fc2d21f3..64b1257f4c 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -1,16 +1,16 @@ // MARK: - PreAuthorizationReview struct PreAuthorizationReview: Sendable, FeatureReducer { typealias Common = InteractionReview + typealias Expiration = DappToWalletInteractionSubintentExpiration struct State: Sendable, Hashable { let unvalidatedManifest: UnvalidatedTransactionManifest + let expiration: Expiration? let nonce: Nonce let signTransactionPurpose: SigningPurpose.SignTransactionPurpose - let ephemeralNotaryPrivateKey: Curve25519.Signing.PrivateKey = .init() let dAppMetadata: DappMetadata.Ledger? var reviewedPreAuthorization: ReviewedPreAuthorization? - var expiration: Expiration? var displayMode: Common.DisplayMode = .detailed var sliderResetDate: Date = .now // TODO: reset when it corresponds @@ -32,13 +32,13 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { } enum InternalAction: Sendable, Equatable { - case previewLoaded(TaskResult) + case previewLoaded(TaskResult) case updateSecondsToExpiration(Date) } @Dependency(\.continuousClock) var clock @Dependency(\.pasteboardClient) var pasteboardClient - @Dependency(\.transactionClient) var transactionClient + @Dependency(\.preAuthorizationClient) var preAuthorizationClient @Dependency(\.errorQueue) var errorQueue var body: some ReducerOf { @@ -53,13 +53,9 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { case .appeared: return .run { [state = state] send in let preview = await TaskResult { - try await transactionClient.getTransactionReview(.init( + try await preAuthorizationClient.getPreview(.init( unvalidatedManifest: state.unvalidatedManifest, - message: .none, - nonce: state.nonce, - ephemeralNotaryPublicKey: state.ephemeralNotaryPrivateKey.publicKey, - signingPurpose: .signTransaction(state.signTransactionPurpose), // Update - isWalletTransaction: true + nonce: state.nonce )) } await send(.internal(.previewLoaded(preview))) @@ -68,11 +64,11 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { case .toggleDisplayModeButtonTapped: switch state.displayMode { case .detailed: - state.displayMode = .raw(state.exampleRaw) + return showRawTransaction(&state) case .raw: state.displayMode = .detailed + return .none } - return .none case .copyRawTransactionButtonTapped: guard let manifest = state.displayMode.rawTransaction else { @@ -92,26 +88,28 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { return .none case let .previewLoaded(.success(preview)): - state.reviewedPreAuthorization = .init(manifest: preview.transactionManifest) + state.reviewedPreAuthorization = .init(manifest: preview.manifest) var effects: [Effect] = [] - let sectionsEffect: Effect - // We will check Preview type to know which type of sections to get - = if 5 > 3 - { - .send(.child(.sections(.internal(.parent(.resolveExecutionSummary( - preview.analyzedManifestToReview, preview.networkID - )))))) - } else { - .send(.child(.sections(.internal(.parent(.resolveTransactionSummary(.init(), preview.networkID)))))) + + // Trigger effect to load sections + let sectionsEffect: Effect = switch preview.kind { + case let .open(value): + .send(.child(.sections(.internal(.parent(.resolveManifestSummary(value.summary, preview.networkID)))))) + case let .enclosed(value): + .send(.child(.sections(.internal(.parent(.resolveExecutionSummary(value.summary, preview.networkID)))))) } effects.append(sectionsEffect) - // Mocking expiration until we have Sargon ready. Timer won't be started if expiration != .atTime - let time = Date().addingTimeInterval(90) - state.expiration = .atTime(time) - state.secondsToExpiration = Int(time.timeIntervalSinceNow) - effects.append(startTimer(expirationDate: time)) + switch state.expiration { + case let .atTime(value): + // Trigger expiration countdown effect + let expirationDate = value.unixTimestampSeconds + state.secondsToExpiration = Int(expirationDate.timeIntervalSinceNow) + effects.append(startTimer(expirationDate: expirationDate)) + case .afterDelay, .none: + break + } return .merge(effects) @@ -131,6 +129,17 @@ private extension PreAuthorizationReview { } .cancellable(id: CancellableId.expirationTimer, cancelInFlight: true) } + + func showRawTransaction(_ state: inout State) -> Effect { + guard let reviewedTransaction = state.reviewedPreAuthorization else { + struct MissingReviewedPreAuthorization: Error {} + errorQueue.schedule(MissingReviewedPreAuthorization()) + return .none + } + // TODO: Confirm if we shouldn't expose manifest.instructionsString + state.displayMode = .raw(reviewedTransaction.manifest.manifestString) + return .none + } } extension PreAuthorizationReview { @@ -139,56 +148,17 @@ extension PreAuthorizationReview { } struct ReviewedPreAuthorization: Sendable, Hashable { - let manifest: TransactionManifest - - // TODO: Fill required info once we have Sargon ready + let manifest: SubintentManifest } } extension PreAuthorizationReview.State { var isExpired: Bool { switch expiration { - case let .atTime(date): - date <= Date.now - case .window, .none: + case let .atTime(value): + value.unixTimestampSeconds <= Date.now + case .afterDelay, .none: false } } } - -extension PreAuthorizationReview.State { - var exampleRaw: String { - """ - CALL_METHOD - Address("account_tdx_2_12ytkalad6hfxamsz4a7r8tevz7ahurfj58dlp4phl4nca5hs0hpu90") - "lock_fee" - Decimal("0.3696274912355") - ; - CALL_METHOD - Address("account_tdx_2_12ytkalad6hfxamsz4a7r8tevz7ahurfj58dlp4phl4nca5hs0hpu90") - "withdraw" - Address("resource_tdx_2_1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxtfd2jc") - Decimal("2") - ; - TAKE_FROM_WORKTOP - Address("resource_tdx_2_1tknxxxxxxxxxradxrdxxxxxxxxx009923554798xxxxxxxxxtfd2jc") - Decimal("2") - Bucket("bucket1") - ; - CALL_METHOD - Address("account_tdx_2_12x2hd6m7z9n389u47sn7qhv3cmeqseyathrpqa2mwlx8wczrpd36ar") - "try_deposit_or_abort" - Bucket("bucket1") - Enum<0u8>() - ; - - """ - } -} - -// MARK: - Expiration -enum Expiration: Sendable, Hashable { - // TODO: Replace with Sargon model - case atTime(Date) - case window(Int) -} From aa3cdd5bb2fc5e6b810f80f5dc7cc91f23433b60 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 28 Oct 2024 17:09:14 -0300 Subject: [PATCH 44/63] handle failure --- .../Models/PreAuthorizationFailure.swift | 9 +++++++++ .../Coordinator/DappInteractionFlow.swift | 10 ++++++++++ .../PreAuthorizationReview.swift | 20 ++++++++++++++++++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/RadixWallet/Clients/PreAuthorizationClient/Models/PreAuthorizationFailure.swift b/RadixWallet/Clients/PreAuthorizationClient/Models/PreAuthorizationFailure.swift index 49da0a8475..cb7492b226 100644 --- a/RadixWallet/Clients/PreAuthorizationClient/Models/PreAuthorizationFailure.swift +++ b/RadixWallet/Clients/PreAuthorizationClient/Models/PreAuthorizationFailure.swift @@ -12,6 +12,15 @@ enum PreAuthorizationFailure: Sendable, LocalizedError, Equatable { } } +extension PreAuthorizationFailure { + var errorKindAndMessage: (errorKind: DappWalletInteractionErrorType, message: String?) { + switch self { + case .failedToGetPreview: + (errorKind: .failedToPrepareTransaction, message: errorDescription) + } + } +} + // MARK: PreAuthorizationFailure.FailedToGetPreview extension PreAuthorizationFailure { enum FailedToGetPreview: Sendable, LocalizedError, Equatable { diff --git a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift index 5cfd960e7d..4aa74ebac3 100644 --- a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift +++ b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift @@ -510,6 +510,13 @@ extension DappInteractionFlow { return continueEffect(for: &state) } + func handlePreAuthorizationFailure( + _ error: PreAuthorizationFailure + ) -> Effect { + let (errorKind, message) = error.errorKindAndMessage + return dismissEffect(for: state, errorKind: errorKind, message: message) + } + let item = state.currentItem guard let action = childAction.action else { return .none } @@ -570,6 +577,9 @@ extension DappInteractionFlow { .accountsProofOfOwnership(.delegate(.failedToSign)): return dismissEffect(for: state, errorKind: .failedToSignAuthChallenge, message: nil) + case let .preAuthorizationReview(.delegate(.failed(error))): + return handlePreAuthorizationFailure(error) + default: return .none } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 64b1257f4c..966be0d4e7 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -36,6 +36,10 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { case updateSecondsToExpiration(Date) } + enum DelegateAction: Sendable, Equatable { + case failed(PreAuthorizationFailure) + } + @Dependency(\.continuousClock) var clock @Dependency(\.pasteboardClient) var pasteboardClient @Dependency(\.preAuthorizationClient) var preAuthorizationClient @@ -85,7 +89,11 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { case let .previewLoaded(.failure(error)): loggerGlobal.error("PreAuthroization preview failed, error: \(error)") errorQueue.schedule(error) - return .none + guard let failure = error as? PreAuthorizationFailure else { + assertionFailure("Failed with unexpected error \(error)") + return .none + } + return .send(.delegate(.failed(failure))) case let .previewLoaded(.success(preview)): state.reviewedPreAuthorization = .init(manifest: preview.manifest) @@ -118,6 +126,16 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { return .none } } + + func reduce(into state: inout State, childAction: ChildAction) -> Effect { + switch childAction { + case .sections(.delegate(.failedToResolveSections)): + showRawTransaction(&state) + + default: + .none + } + } } private extension PreAuthorizationReview { From 0cb534757ecedc10e8f4f8dfe1ce73e6417c3ef1 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 29 Oct 2024 12:04:39 -0300 Subject: [PATCH 45/63] move raw alert to parent views --- .../Sections/Sections+View.swift | 6 +-- .../InteractionReview/Sections/Sections.swift | 21 --------- .../PreAuthorizationReview+View.swift | 26 +++++++++- .../PreAuthorizationReview.swift | 47 +++++++++++++++---- .../TransactionReview+View.swift | 5 ++ .../TransactionReview.swift | 17 +++++++ 6 files changed, 86 insertions(+), 36 deletions(-) diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift index 71f88c56ff..4b600a7b80 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift @@ -39,6 +39,7 @@ extension InteractionReview.Sections { var isExpandedClaimingFromValidators: Bool { claimingFromValidators?.isExpanded == true } } + @MainActor struct View: SwiftUI.View { let store: StoreOf @@ -270,11 +271,6 @@ private extension View { .lsuDetails(with: destinationStore) .poolUnitDetails(with: destinationStore) .unknownComponents(with: destinationStore) - .rawTransactionAlert(with: destinationStore) - } - - private func rawTransactionAlert(with destinationStore: PresentationStoreOf) -> some View { - alert(store: destinationStore.scope(state: \.rawTransactionAlert, action: \.rawTransactionAlert)) } private func dApp(with destinationStore: PresentationStoreOf) -> some View { diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections.swift b/RadixWallet/Features/InteractionReview/Sections/Sections.swift index 37152f79c7..ce13419894 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections.swift @@ -73,7 +73,6 @@ extension InteractionReview { case poolUnitDetails(PoolUnitDetails.State) case lsuDetails(LSUDetails.State) case unknownDappComponents(Common.UnknownDappComponents.State) - case rawTransactionAlert(AlertState) } @CasePathable @@ -84,11 +83,6 @@ extension InteractionReview { case lsuDetails(LSUDetails.Action) case poolUnitDetails(PoolUnitDetails.Action) case unknownDappComponents(Common.UnknownDappComponents.Action) - case rawTransactionAlert(RawTransactionAlert) - - enum RawTransactionAlert: Sendable, Equatable { - case continueTapped - } } var body: some ReducerOf { @@ -175,7 +169,6 @@ extension InteractionReview { case let .setSections(sections): guard let sections else { - state.destination = .rawTransactionAlert(.rawTransaction) return .send(.delegate(.failedToResolveSections)) } state.withdrawals = sections.withdrawals @@ -313,17 +306,3 @@ private extension InteractionReview.Sections { return .none } } - -extension AlertState { - static var rawTransaction: AlertState { - AlertState { - TextState(L10n.TransactionReview.NonConformingManifestWarning.title) - } actions: { - ButtonState(action: .continueTapped) { - TextState(L10n.Common.continue) - } - } message: { - TextState(L10n.TransactionReview.NonConformingManifestWarning.message) - } - } -} diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index ea766d2653..f465a6f16a 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -32,6 +32,7 @@ extension PreAuthorizationReview { } } + @MainActor struct View: SwiftUI.View { let store: StoreOf @@ -56,6 +57,7 @@ extension PreAuthorizationReview { .onAppear { store.send(.view(.appeared)) } + .destinations(with: store) } } @@ -131,7 +133,7 @@ extension PreAuthorizationReview { private func rawTransaction(_ content: String) -> some SwiftUI.View { Common.RawTransactionView(transaction: content) { - store.send(.view(.copyRawTransactionButtonTapped)) + store.send(.view(.copyRawManifestButtonTapped)) } toggleAction: { store.send(.view(.toggleDisplayModeButtonTapped)) } @@ -151,6 +153,7 @@ extension PreAuthorizationReview { .padding(.medium3) } } + .frame(minHeight: .standardButtonHeight + 2 * .medium3, alignment: .top) } private var sections: some SwiftUI.View { @@ -250,3 +253,24 @@ private extension PreAuthorizationReview.State { globalControlState == .enabled } } + +extension StoreOf { + var destination: PresentationStoreOf { + func scopeState(state: State) -> PresentationState { + state.$destination + } + return scope(state: scopeState, action: Action.destination) + } +} + +@MainActor +private extension View { + func destinations(with store: StoreOf) -> some View { + let destinationStore = store.destination + return rawManifestAlert(with: destinationStore) + } + + private func rawManifestAlert(with destinationStore: PresentationStoreOf) -> some View { + alert(store: destinationStore.scope(state: \.rawManifestAlert, action: \.rawManifestAlert)) + } +} diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 966be0d4e7..cc882dc378 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -18,12 +18,15 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { // Sections var sections: Common.Sections.State = .init(kind: .preAuthorization) + + @PresentationState + var destination: Destination.State? = nil } enum ViewAction: Sendable, Equatable { case appeared case toggleDisplayModeButtonTapped - case copyRawTransactionButtonTapped + case copyRawManifestButtonTapped } @CasePathable @@ -40,6 +43,26 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { case failed(PreAuthorizationFailure) } + struct Destination: DestinationReducer { + @CasePathable + enum State: Sendable, Hashable { + case signing(Signing.State) + case rawManifestAlert(AlertState) + } + + @CasePathable + enum Action: Sendable, Equatable { + case signing(Signing.Action) + case rawManifestAlert(Never) + } + + var body: some ReducerOf { + Scope(state: \.signing, action: \.signing) { + Signing() + } + } + } + @Dependency(\.continuousClock) var clock @Dependency(\.pasteboardClient) var pasteboardClient @Dependency(\.preAuthorizationClient) var preAuthorizationClient @@ -50,8 +73,13 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { Common.Sections() } Reduce(core) + .ifLet(destinationPath, action: \.destination) { + Destination() + } } + private let destinationPath: WritableKeyPath> = \.$destination + func reduce(into state: inout State, viewAction: ViewAction) -> Effect { switch viewAction { case .appeared: @@ -68,13 +96,13 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { case .toggleDisplayModeButtonTapped: switch state.displayMode { case .detailed: - return showRawTransaction(&state) + return showRawManifest(&state) case .raw: state.displayMode = .detailed return .none } - case .copyRawTransactionButtonTapped: + case .copyRawManifestButtonTapped: guard let manifest = state.displayMode.rawTransaction else { assertionFailure("Copy raw manifest button should only be visible in raw transaction mode") return .none @@ -130,10 +158,11 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { func reduce(into state: inout State, childAction: ChildAction) -> Effect { switch childAction { case .sections(.delegate(.failedToResolveSections)): - showRawTransaction(&state) + state.destination = .rawManifestAlert(.rawTransaction) + return showRawManifest(&state) default: - .none + return .none } } } @@ -148,14 +177,14 @@ private extension PreAuthorizationReview { .cancellable(id: CancellableId.expirationTimer, cancelInFlight: true) } - func showRawTransaction(_ state: inout State) -> Effect { - guard let reviewedTransaction = state.reviewedPreAuthorization else { + func showRawManifest(_ state: inout State) -> Effect { + guard let reviewedPreAuthorization = state.reviewedPreAuthorization else { struct MissingReviewedPreAuthorization: Error {} errorQueue.schedule(MissingReviewedPreAuthorization()) return .none } - // TODO: Confirm if we shouldn't expose manifest.instructionsString - state.displayMode = .raw(reviewedTransaction.manifest.manifestString) + + state.displayMode = .raw(reviewedPreAuthorization.manifest.manifestString) return .none } } diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index c8fbff7865..47ce97b390 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -236,6 +236,7 @@ private extension View { .customizeFees(with: destinationStore) .signing(with: destinationStore) .submitting(with: destinationStore) + .rawTransactionAlert(with: destinationStore) } private func customizeGuarantees(with destinationStore: PresentationStoreOf) -> some View { @@ -273,6 +274,10 @@ private extension View { content: { SubmitTransaction.View(store: $0) } ) } + + private func rawTransactionAlert(with destinationStore: PresentationStoreOf) -> some View { + alert(store: destinationStore.scope(state: \.rawTransactionAlert, action: \.rawTransactionAlert)) + } } // MARK: - TransactionMessageView diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift index ab27329244..b0ff31736f 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift @@ -114,18 +114,22 @@ struct TransactionReview: Sendable, FeatureReducer { } struct Destination: DestinationReducer { + @CasePathable enum State: Sendable, Hashable { case customizeGuarantees(TransactionReviewGuarantees.State) case signing(Signing.State) case submitting(SubmitTransaction.State) case customizeFees(CustomizeFees.State) + case rawTransactionAlert(AlertState) } + @CasePathable enum Action: Sendable, Equatable { case customizeGuarantees(TransactionReviewGuarantees.Action) case signing(Signing.Action) case submitting(SubmitTransaction.Action) case customizeFees(CustomizeFees.Action) + case rawTransactionAlert(Never) } var body: some ReducerOf { @@ -258,6 +262,7 @@ struct TransactionReview: Sendable, FeatureReducer { case let .sections(.delegate(delegateAction)): switch delegateAction { case .failedToResolveSections: + state.destination = .rawTransactionAlert(.rawTransaction) return showRawTransaction(&state) case let .showCustomizeGuarantees(guarantees): @@ -790,6 +795,18 @@ extension ReviewedTransaction { } } +extension AlertState { + static var rawTransaction: AlertState { + AlertState { + TextState(L10n.TransactionReview.NonConformingManifestWarning.title) + } actions: { + .default(TextState(L10n.Common.continue)) + } message: { + TextState(L10n.TransactionReview.NonConformingManifestWarning.message) + } + } +} + #if DEBUG func printSigners(_ reviewedTransaction: ReviewedTransaction) { for (factorSourceKind, signingFactorsOfKind) in reviewedTransaction.signingFactors { From 3b2f76edc11f6e08c378391b2daecb23fe6776c8 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 29 Oct 2024 13:25:09 -0300 Subject: [PATCH 46/63] add button to create sample PreAuthorization from Account Dev Preferences --- .../Models/WalletInteraction+Extensions.swift | 14 ++++++++++ .../DevAccountPreferences+Reducer.swift | 27 +++++++++++++++++++ .../Children/DevAccountPreferences+View.swift | 4 +++ 3 files changed, 45 insertions(+) diff --git a/RadixWallet/Core/SharedModels/P2P/Dapp/Models/WalletInteraction+Extensions.swift b/RadixWallet/Core/SharedModels/P2P/Dapp/Models/WalletInteraction+Extensions.swift index d6e43a0dfa..6664cafe1b 100644 --- a/RadixWallet/Core/SharedModels/P2P/Dapp/Models/WalletInteraction+Extensions.swift +++ b/RadixWallet/Core/SharedModels/P2P/Dapp/Models/WalletInteraction+Extensions.swift @@ -41,6 +41,20 @@ extension DappToWalletInteractionSendTransactionItem { } } +extension DappToWalletInteractionSubintentRequestItem { + init( + unvalidatedManifest: UnvalidatedTransactionManifest, + expiration: DappToWalletInteractionSubintentExpiration? = nil + ) { + self.init( + version: .default, + unvalidatedManifest: unvalidatedManifest, + message: nil, + expiration: expiration + ) + } +} + // MARK: - DappToWalletInteraction.RequestValidation extension DappToWalletInteraction { struct RequestValidation: Sendable, Hashable { diff --git a/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+Reducer.swift b/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+Reducer.swift index 35ea258657..e54db75334 100644 --- a/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+Reducer.swift +++ b/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+Reducer.swift @@ -49,6 +49,7 @@ struct DevAccountPreferences: Sendable, FeatureReducer { case createNonFungibleTokenButtonTapped case createMultipleFungibleTokenButtonTapped case createMultipleNonFungibleTokenButtonTapped + case createPreAuthorizationButtonTapped case deleteAccountButtonTapped #endif // DEBUG } @@ -96,6 +97,7 @@ struct DevAccountPreferences: Sendable, FeatureReducer { @Dependency(\.accountsClient) var accountsClient @Dependency(\.errorQueue) var errorQueue + @Dependency(\.dappInteractionClient) var dappInteractionClient #if DEBUG @Dependency(\.gatewayAPIClient) var gatewayAPIClient @@ -198,6 +200,31 @@ struct DevAccountPreferences: Sendable, FeatureReducer { } catch: { error, _ in loggerGlobal.warning("Failed to create manifest which turns account into dapp definition account type, error: \(error)") } + case .createPreAuthorizationButtonTapped: + return .run { _ in + let manifest = """ + CALL_METHOD + Address("component_tdx_2_1cptxxxxxxxxxfaucetxxxxxxxxx000527798379xxxxxxxxxyulkzl") + "free" + ; + + CALL_METHOD + Address("account_tdx_2_1299trm47s3x648jemhu3lfm4d6gt73289rd9s2hpdjm3tp5pdwq4m5") + "try_deposit_batch_or_abort" + Expression("ENTIRE_WORKTOP") + Enum<0u8>() + ; + + YIELD_TO_PARENT; + """ + let unvalidated = UnvalidatedTransactionManifest(transactionManifestString: manifest, blobs: Blobs([])) + + _ = await dappInteractionClient.addWalletInteraction( + .preAuthorization(.init(request: .init(unvalidatedManifest: unvalidated))), + .accountTransfer + ) + } + #endif } } diff --git a/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+View.swift b/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+View.swift index 26bd98b8a1..2a37f25050 100644 --- a/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+View.swift +++ b/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+View.swift @@ -72,6 +72,10 @@ extension DevAccountPreferences { createNonFungibleTokenButton(with: viewStore) createMultipleFungibleTokenButton(with: viewStore) createMultipleNonFungibleTokenButton(with: viewStore) + Button("Create PreAuthorization") { + viewStore.send(.createPreAuthorizationButtonTapped) + } + .buttonStyle(.secondaryRectangular(shouldExpand: true)) Spacer(minLength: 0) deleteAccountButton { store.send(.view(.deleteAccountButtonTapped)) } #endif // DEBUG From 7852725a50751e5a6384c060ad0e8440fa983e5e Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 29 Oct 2024 14:46:29 -0300 Subject: [PATCH 47/63] delete ReviewRawTransactionView --- RadixWallet.xcodeproj/project.pbxproj | 16 ------ ...TransactionReviewRawTransaction+View.swift | 50 ------------------- .../TransactionReviewRawTransaction.swift | 30 ----------- 3 files changed, 96 deletions(-) delete mode 100644 RadixWallet/Features/TransactionReviewFeature/TransactionReviewRawTransaction/TransactionReviewRawTransaction+View.swift delete mode 100644 RadixWallet/Features/TransactionReviewFeature/TransactionReviewRawTransaction/TransactionReviewRawTransaction.swift diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index c30cf46ce2..67d8f1d7f8 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -129,8 +129,6 @@ 48CFC28A2ADC10D900E77A5C /* TransactionReviewGuarantees.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCDD2ADC10D800E77A5C /* TransactionReviewGuarantees.swift */; }; 48CFC28B2ADC10D900E77A5C /* Proofs+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCDF2ADC10D800E77A5C /* Proofs+View.swift */; }; 48CFC28C2ADC10D900E77A5C /* Proofs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCE02ADC10D800E77A5C /* Proofs.swift */; }; - 48CFC28D2ADC10D900E77A5C /* TransactionReviewRawTransaction+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCE22ADC10D800E77A5C /* TransactionReviewRawTransaction+View.swift */; }; - 48CFC28E2ADC10D900E77A5C /* TransactionReviewRawTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCE32ADC10D800E77A5C /* TransactionReviewRawTransaction.swift */; }; 48CFC28F2ADC10D900E77A5C /* Accounts+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCE52ADC10D800E77A5C /* Accounts+View.swift */; }; 48CFC2902ADC10D900E77A5C /* Accounts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCE62ADC10D800E77A5C /* Accounts.swift */; }; 48CFC2912ADC10D900E77A5C /* TransactionReviewNetworkFee+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CFBCE82ADC10D800E77A5C /* TransactionReviewNetworkFee+View.swift */; }; @@ -1402,8 +1400,6 @@ 48CFBCDD2ADC10D800E77A5C /* TransactionReviewGuarantees.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionReviewGuarantees.swift; sourceTree = ""; }; 48CFBCDF2ADC10D800E77A5C /* Proofs+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Proofs+View.swift"; sourceTree = ""; }; 48CFBCE02ADC10D800E77A5C /* Proofs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Proofs.swift; sourceTree = ""; }; - 48CFBCE22ADC10D800E77A5C /* TransactionReviewRawTransaction+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TransactionReviewRawTransaction+View.swift"; sourceTree = ""; }; - 48CFBCE32ADC10D800E77A5C /* TransactionReviewRawTransaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionReviewRawTransaction.swift; sourceTree = ""; }; 48CFBCE52ADC10D800E77A5C /* Accounts+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Accounts+View.swift"; sourceTree = ""; }; 48CFBCE62ADC10D800E77A5C /* Accounts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Accounts.swift; sourceTree = ""; }; 48CFBCE82ADC10D800E77A5C /* TransactionReviewNetworkFee+View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TransactionReviewNetworkFee+View.swift"; sourceTree = ""; }; @@ -3030,7 +3026,6 @@ 48CFBCD12ADC10D800E77A5C /* SelectFeePayer */, 48CFBCD52ADC10D800E77A5C /* SubmitTransaction */, 48CFBCD82ADC10D800E77A5C /* TransactionReviewGuarantees */, - 48CFBCE12ADC10D800E77A5C /* TransactionReviewRawTransaction */, 48CFBCE72ADC10D800E77A5C /* TransactionReviewNetworkFee */, 48CFBCEA2ADC10D800E77A5C /* CustomizeFees */, ); @@ -3083,15 +3078,6 @@ path = Proofs; sourceTree = ""; }; - 48CFBCE12ADC10D800E77A5C /* TransactionReviewRawTransaction */ = { - isa = PBXGroup; - children = ( - 48CFBCE22ADC10D800E77A5C /* TransactionReviewRawTransaction+View.swift */, - 48CFBCE32ADC10D800E77A5C /* TransactionReviewRawTransaction.swift */, - ); - path = TransactionReviewRawTransaction; - sourceTree = ""; - }; 48CFBCE42ADC10D800E77A5C /* Accounts */ = { isa = PBXGroup; children = ( @@ -7598,7 +7584,6 @@ 48CFC2852ADC10D900E77A5C /* SubmitTransaction+View.swift in Sources */, A40815632C7E0D08005E65B9 /* AccountLockerVaultCollectionItemType.swift in Sources */, 48CFC47C2ADC10DA00E77A5C /* TransportProfileClient+Test.swift in Sources */, - 48CFC28D2ADC10D900E77A5C /* TransactionReviewRawTransaction+View.swift in Sources */, 48CFC2C92ADC10D900E77A5C /* FungibleResourceAsset+View.swift in Sources */, 5B6E11482C45835900C20F2D /* AccountCard+DataSource.swift in Sources */, 48CFC40F2ADC10DA00E77A5C /* Logger.swift in Sources */, @@ -8101,7 +8086,6 @@ 48CFC4452ADC10DA00E77A5C /* OnboardingClient+Test.swift in Sources */, 48CFC32C2ADC10D900E77A5C /* ScanQR+Reducer.swift in Sources */, 48CFC37A2ADC10D900E77A5C /* PoolUnitDetails.swift in Sources */, - 48CFC28E2ADC10D900E77A5C /* TransactionReviewRawTransaction.swift in Sources */, 48CFC6042ADC10DA00E77A5C /* ConnectorExtension+Messages.swift in Sources */, 48CFC65D2ADC10DB00E77A5C /* Profile+AuthorizedDapps+Edit.swift in Sources */, E7A5AC9D2C108F2F006CB6EC /* WalletInteraction+Extensions.swift in Sources */, diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewRawTransaction/TransactionReviewRawTransaction+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReviewRawTransaction/TransactionReviewRawTransaction+View.swift deleted file mode 100644 index 88aefcc6d1..0000000000 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewRawTransaction/TransactionReviewRawTransaction+View.swift +++ /dev/null @@ -1,50 +0,0 @@ -import ComposableArchitecture -import SwiftUI - -// MARK: - TransactionReviewRawTransaction.View -extension TransactionReviewRawTransaction { - @MainActor - struct View: SwiftUI.View { - let store: StoreOf - - init(store: StoreOf) { - self.store = store - } - - var body: some SwiftUI.View { - WithViewStore(store, observe: { $0 }, send: { .view($0) }) { viewStore in - NavigationStack { - ScrollView { - RawTransactionView(transaction: viewStore.transaction) - } - .radixToolbar(title: L10n.TransactionReview.rawTransactionTitle, alwaysVisible: false) - .toolbar { - ToolbarItem(placement: .cancellationAction) { - CloseButton { - viewStore.send(.closeTapped) - } - } - } - } - .background(Color(white: 0.9)) - } - } - - struct RawTransactionView: SwiftUI.View { - let transaction: String - - var body: some SwiftUI.View { - Text(transaction) - .textStyle(.monospace) - .foregroundColor(.app.gray1) - .frame( - maxWidth: .infinity, - maxHeight: .infinity, - alignment: .topLeading - ) - .padding() - .multilineTextAlignment(.leading) - } - } - } -} diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewRawTransaction/TransactionReviewRawTransaction.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReviewRawTransaction/TransactionReviewRawTransaction.swift deleted file mode 100644 index 2c2e3071ce..0000000000 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReviewRawTransaction/TransactionReviewRawTransaction.swift +++ /dev/null @@ -1,30 +0,0 @@ -import ComposableArchitecture -import SwiftUI - -// MARK: - TransactionReviewRawTransaction -struct TransactionReviewRawTransaction: Sendable, FeatureReducer { - @Dependency(\.dismiss) var dismiss - - struct State: Sendable, Hashable { - var transaction: String - - init(transaction: String) { - self.transaction = transaction - } - } - - enum ViewAction: Sendable, Equatable { - case closeTapped - } - - init() {} - - func reduce(into state: inout State, viewAction: ViewAction) -> Effect { - switch viewAction { - case .closeTapped: - .run { _ in - await dismiss() - } - } - } -} From d65e57d517dedd0bb26898c171da0991eaad97b7 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 29 Oct 2024 16:11:19 -0300 Subject: [PATCH 48/63] update to RawManifest view --- RadixWallet.xcodeproj/project.pbxproj | 8 +++---- ...actionView.swift => RawManifestView.swift} | 10 ++++----- .../Helpers/DisplayMode.swift | 6 ++--- .../PreAuthorizationReview+View.swift | 22 +++++++++---------- .../PreAuthorizationReview.swift | 18 ++++++++++++--- .../TransactionReview+View.swift | 18 +++++++-------- .../TransactionReview.swift | 2 +- 7 files changed, 48 insertions(+), 36 deletions(-) rename RadixWallet/Features/InteractionReview/Components/{RawTransactionView.swift => RawManifestView.swift} (89%) diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index 67d8f1d7f8..f562355d4d 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -708,7 +708,7 @@ 48FFFB0A2ADC721800B2B213 /* Atomics in Frameworks */ = {isa = PBXBuildFile; productRef = 48FFFB092ADC721800B2B213 /* Atomics */; }; 48FFFB0D2ADC744700B2B213 /* TextBuilder in Frameworks */ = {isa = PBXBuildFile; productRef = 48FFFB0C2ADC744700B2B213 /* TextBuilder */; }; 5B03E3CF2CC1223000E10A64 /* DisplayMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B03E3CE2CC1222D00E10A64 /* DisplayMode.swift */; }; - 5B03E3D12CC127B100E10A64 /* RawTransactionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */; }; + 5B03E3D12CC127B100E10A64 /* RawManifestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B03E3D02CC127B100E10A64 /* RawManifestView.swift */; }; 5B03E3D32CC141D100E10A64 /* InteractionReview+Extra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B03E3D22CC141C200E10A64 /* InteractionReview+Extra.swift */; }; 5B03E3D52CC1487900E10A64 /* TransferLineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */; }; 5B135B392C7636DA004AAD2E /* HiddenEntities+View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B135B382C7636DA004AAD2E /* HiddenEntities+View.swift */; }; @@ -1949,7 +1949,7 @@ 48FF43142AE43C7C00C568B9 /* TimeLimit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeLimit.swift; sourceTree = ""; }; 48FFFAF12ADC23AC00B2B213 /* Exports.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Exports.swift; sourceTree = ""; }; 5B03E3CE2CC1222D00E10A64 /* DisplayMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayMode.swift; sourceTree = ""; }; - 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawTransactionView.swift; sourceTree = ""; }; + 5B03E3D02CC127B100E10A64 /* RawManifestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawManifestView.swift; sourceTree = ""; }; 5B03E3D22CC141C200E10A64 /* InteractionReview+Extra.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InteractionReview+Extra.swift"; sourceTree = ""; }; 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransferLineView.swift; sourceTree = ""; }; 5B135B382C7636DA004AAD2E /* HiddenEntities+View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HiddenEntities+View.swift"; sourceTree = ""; }; @@ -5542,7 +5542,7 @@ 5B27FBD82CC67655002975BE /* HeadingView.swift */, 5B27FBEB2CC70E87002975BE /* ExpandableHeadingView.swift */, 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */, - 5B03E3D02CC127B100E10A64 /* RawTransactionView.swift */, + 5B03E3D02CC127B100E10A64 /* RawManifestView.swift */, 5B4A1AC52CC0150D00679EE6 /* HeaderView.swift */, 5B27FBE92CC70C9D002975BE /* ValidatorsView.swift */, ); @@ -8133,7 +8133,7 @@ A40815FA2C7E0D08005E65B9 /* ScryptoSborValue.swift in Sources */, 48CFC5F02ADC10DA00E77A5C /* UserDefaultsClient+AccountRecovery.swift in Sources */, A408161A2C7E0D08005E65B9 /* StateEntityNonFungibleResourceVaultsPageRequest.swift in Sources */, - 5B03E3D12CC127B100E10A64 /* RawTransactionView.swift in Sources */, + 5B03E3D12CC127B100E10A64 /* RawManifestView.swift in Sources */, 48CFC3562ADC10D900E77A5C /* ImportOlympiaLedgerAccountsAndFactorSources.swift in Sources */, 48CFC5782ADC10DA00E77A5C /* GatewayError.swift in Sources */, 48CFC5E62ADC10DA00E77A5C /* SwiftUINavigation+Extra.swift in Sources */, diff --git a/RadixWallet/Features/InteractionReview/Components/RawTransactionView.swift b/RadixWallet/Features/InteractionReview/Components/RawManifestView.swift similarity index 89% rename from RadixWallet/Features/InteractionReview/Components/RawTransactionView.swift rename to RadixWallet/Features/InteractionReview/Components/RawManifestView.swift index a66c7cd3a3..b0652aad5a 100644 --- a/RadixWallet/Features/InteractionReview/Components/RawTransactionView.swift +++ b/RadixWallet/Features/InteractionReview/Components/RawManifestView.swift @@ -1,17 +1,17 @@ import SwiftUI extension InteractionReview { - struct RawTransactionView: SwiftUI.View { - let transaction: String + struct RawManifestView: SwiftUI.View { + let manifest: String let copyAction: () -> Void let toggleAction: (() -> Void)? init( - transaction: String, + manifest: String, copyAction: @escaping () -> Void, toggleAction: (() -> Void)? = nil ) { - self.transaction = transaction + self.manifest = manifest self.copyAction = copyAction self.toggleAction = toggleAction } @@ -54,7 +54,7 @@ extension InteractionReview { } private var content: some View { - Text(transaction) + Text(manifest) .textStyle(.monospace) .foregroundColor(.app.gray1) .multilineTextAlignment(.leading) diff --git a/RadixWallet/Features/InteractionReview/Helpers/DisplayMode.swift b/RadixWallet/Features/InteractionReview/Helpers/DisplayMode.swift index 1c6dfce84e..75d4ce8022 100644 --- a/RadixWallet/Features/InteractionReview/Helpers/DisplayMode.swift +++ b/RadixWallet/Features/InteractionReview/Helpers/DisplayMode.swift @@ -5,9 +5,9 @@ extension InteractionReview { case detailed case raw(String) - var rawTransaction: String? { - guard case let .raw(transaction) = self else { return nil } - return transaction + var rawManifest: String? { + guard case let .raw(manifest) = self else { return nil } + return manifest } } } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index f465a6f16a..6b038d342e 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -10,7 +10,7 @@ extension PreAuthorizationReview.State { secondsToExpiration: secondsToExpiration, globalControlState: globalControlState, sliderControlState: sliderControlState, - showRawTransactionButton: showRawTransactionButton + showRawManifestButton: showRawManifestButton ) } } @@ -25,7 +25,7 @@ extension PreAuthorizationReview { let secondsToExpiration: Int? let globalControlState: ControlState let sliderControlState: ControlState - let showRawTransactionButton: Bool + let showRawManifestButton: Bool var dAppName: String? { dAppMetadata?.name?.rawValue @@ -81,10 +81,10 @@ extension PreAuthorizationReview { header(dAppMetadata: viewStore.dAppMetadata) Group { - if let rawContent = viewStore.displayMode.rawTransaction { - rawTransaction(rawContent) + if let manifest = viewStore.displayMode.rawManifest { + rawManifest(manifest) } else { - details(viewStore.showRawTransactionButton) + details(viewStore.showRawManifestButton) } } .background(Common.gradientBackground) @@ -104,7 +104,7 @@ extension PreAuthorizationReview { .controlState(viewStore.sliderControlState) .padding(.horizontal, .medium2) } - .animation(.easeInOut, value: viewStore.displayMode.rawTransaction) + .animation(.easeInOut, value: viewStore.displayMode.rawManifest) } .coordinateSpace(name: coordSpace) .onPreferenceChange(PositionsPreferenceKey.self) { positions in @@ -131,21 +131,21 @@ extension PreAuthorizationReview { .padding(.bottom, .medium3) } - private func rawTransaction(_ content: String) -> some SwiftUI.View { - Common.RawTransactionView(transaction: content) { + private func rawManifest(_ manifest: String) -> some SwiftUI.View { + Common.RawManifestView(manifest: manifest) { store.send(.view(.copyRawManifestButtonTapped)) } toggleAction: { store.send(.view(.toggleDisplayModeButtonTapped)) } } - private func details(_ showRawTransactionButton: Bool) -> some SwiftUI.View { + private func details(_ showRawManifestButton: Bool) -> some SwiftUI.View { sections .padding(.top, .large2 + .small3) .padding(.horizontal, .small1) .padding(.bottom, .medium1) .overlay(alignment: .topTrailing) { - if showRawTransactionButton { + if showRawManifestButton { Button(asset: AssetResource.code) { store.send(.view(.toggleDisplayModeButtonTapped)) } @@ -249,7 +249,7 @@ private extension PreAuthorizationReview.State { isExpired ? .disabled : globalControlState } - var showRawTransactionButton: Bool { + var showRawManifestButton: Bool { globalControlState == .enabled } } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index cc882dc378..14d5680319 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -103,8 +103,8 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { } case .copyRawManifestButtonTapped: - guard let manifest = state.displayMode.rawTransaction else { - assertionFailure("Copy raw manifest button should only be visible in raw transaction mode") + guard let manifest = state.displayMode.rawManifest else { + assertionFailure("Copy raw manifest button should only be visible in raw mode") return .none } pasteboardClient.copyString(manifest) @@ -158,7 +158,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { func reduce(into state: inout State, childAction: ChildAction) -> Effect { switch childAction { case .sections(.delegate(.failedToResolveSections)): - state.destination = .rawManifestAlert(.rawTransaction) + state.destination = .rawManifestAlert(.rawManifest) return showRawManifest(&state) default: @@ -209,3 +209,15 @@ extension PreAuthorizationReview.State { } } } + +private extension AlertState { + static var rawManifest: AlertState { + AlertState { + TextState("Warning") + } actions: { + .default(TextState(L10n.Common.continue)) + } message: { + TextState("This is a complex pre-authorization that cannot be summarized - the raw pre-authorization manifest will be shown. Do not sign and return unless you understand the contents.") + } + } +} diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index 47ce97b390..40825abc85 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -18,12 +18,12 @@ extension TransactionReview.State { .init( message: message.plaintext, viewControlState: viewControlState, - rawTransaction: displayMode.rawTransaction, + rawManifest: displayMode.rawManifest, showApprovalSlider: reviewedTransaction != nil, canApproveTX: canApproveTX && reviewedTransaction?.feePayingValidation.wrappedValue?.isValid == true, sliderResetDate: sliderResetDate, canToggleViewMode: reviewedTransaction != nil && reviewedTransaction?.isNonConforming == false, - viewRawTransactionButtonState: reviewedTransaction?.feePayer.isSuccess == true ? .enabled : .disabled, + viewRawManifestButtonState: reviewedTransaction?.feePayer.isSuccess == true ? .enabled : .disabled, proposingDappMetadata: proposingDappMetadata ) } @@ -43,12 +43,12 @@ extension TransactionReview { let message: String? let viewControlState: ControlState - let rawTransaction: String? + let rawManifest: String? let showApprovalSlider: Bool let canApproveTX: Bool let sliderResetDate: Date let canToggleViewMode: Bool - let viewRawTransactionButtonState: ControlState + let viewRawManifestButtonState: ControlState let proposingDappMetadata: DappMetadata.Ledger? var approvalSliderControlState: ControlState { @@ -84,9 +84,9 @@ extension TransactionReview { Button(asset: AssetResource.iconTxnBlocks) { viewStore.send(.showRawTransactionTapped) } - .controlState(viewStore.viewRawTransactionButtonState) + .controlState(viewStore.viewRawManifestButtonState) .buttonStyle(.secondaryRectangular(isInToolbar: true)) - .brightness(viewStore.rawTransaction == nil ? 0 : -0.15) + .brightness(viewStore.rawManifest == nil ? 0 : -0.15) } } @@ -119,8 +119,8 @@ extension TransactionReview { VStack(spacing: 0) { header(viewStore.proposingDappMetadata) - if let rawTransaction = viewStore.rawTransaction { - Common.RawTransactionView(transaction: rawTransaction) { + if let manifest = viewStore.rawManifest { + Common.RawManifestView(manifest: manifest) { viewStore.send(.copyRawTransactionTapped) } } else { @@ -158,7 +158,7 @@ extension TransactionReview { } } .background(Common.gradientBackground) - .animation(.easeInOut, value: viewStore.canToggleViewMode ? viewStore.rawTransaction : nil) + .animation(.easeInOut, value: viewStore.canToggleViewMode ? viewStore.rawManifest : nil) } .coordinateSpace(name: coordSpace) .onPreferenceChange(PositionsPreferenceKey.self) { positions in diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift index b0ff31736f..4b9c25bea1 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift @@ -795,7 +795,7 @@ extension ReviewedTransaction { } } -extension AlertState { +private extension AlertState { static var rawTransaction: AlertState { AlertState { TextState(L10n.TransactionReview.NonConformingManifestWarning.title) From 6ccdbdfc54790a18fad4b14c54ecd4559bce4387 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Wed, 30 Oct 2024 10:50:10 -0300 Subject: [PATCH 49/63] update with latest Sargon version --- RadixWallet.xcodeproj/project.pbxproj | 19 +- .../xcshareddata/swiftpm/Package.resolved | 428 ++++++++++++++++++ .../PreAuthorizationClient+Interface.swift | 2 +- .../PreAuthorizationClient+Live.swift | 2 +- .../Models/WalletInteraction+Extensions.swift | 2 +- .../DevAccountPreferences+Reducer.swift | 5 +- .../PreAuthorizationReview.swift | 2 +- 7 files changed, 445 insertions(+), 15 deletions(-) create mode 100644 RadixWallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index f562355d4d..159346b1ce 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 60; + objectVersion = 56; objects = { /* Begin PBXBuildFile section */ @@ -7106,7 +7106,7 @@ 8318BB172BC8403800057BCB /* XCRemoteSwiftPackageReference "swift-custom-dump" */, E6A0B0492BF23C7000617DAC /* XCRemoteSwiftPackageReference "swift-identified-collections" */, 5B634A922C91D2A0004B2FBC /* XCRemoteSwiftPackageReference "ScreenshotPreventing-iOS" */, - 5B84339D2CD00D6B00CA00F5 /* XCLocalSwiftPackageReference "../sargon" */, + 5B3047A72CD26EB1009FAF90 /* XCRemoteSwiftPackageReference "sargon" */, ); productRefGroup = 48CFBC502ADC106300E77A5C /* Products */; projectDirPath = ""; @@ -8933,13 +8933,6 @@ }; /* End XCConfigurationList section */ -/* Begin XCLocalSwiftPackageReference section */ - 5B84339D2CD00D6B00CA00F5 /* XCLocalSwiftPackageReference "../sargon" */ = { - isa = XCLocalSwiftPackageReference; - relativePath = ../sargon; - }; -/* End XCLocalSwiftPackageReference section */ - /* Begin XCRemoteSwiftPackageReference section */ 48FFFA972ADC1EEC00B2B213 /* XCRemoteSwiftPackageReference "AsyncExtensions" */ = { isa = XCRemoteSwiftPackageReference; @@ -9173,6 +9166,14 @@ version = 6.13.2; }; }; + 5B3047A72CD26EB1009FAF90 /* XCRemoteSwiftPackageReference "sargon" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/radixdlt/sargon/"; + requirement = { + kind = exactVersion; + version = 1.1.42; + }; + }; 5B4E1D1D2CB7FE8E002FAC2E /* XCRemoteSwiftPackageReference "sargon" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/radixdlt/sargon/"; diff --git a/RadixWallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/RadixWallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000000..10ffa8c97a --- /dev/null +++ b/RadixWallet.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,428 @@ +{ + "originHash" : "7f25d08c2d5bfce10ead9a90a371e548d360b6e5e8779b8ad654bfac475f1dc8", + "pins" : [ + { + "identity" : "anycodable", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Flight-School/AnyCodable", + "state" : { + "revision" : "862808b2070cd908cb04f9aafe7de83d35f81b05", + "version" : "0.6.7" + } + }, + { + "identity" : "appsflyerframework-strict", + "kind" : "remoteSourceControl", + "location" : "https://github.com/AppsFlyerSDK/AppsFlyerFramework-Strict", + "state" : { + "revision" : "a22ea3af34d4631123bd54f55f95f7b7a9cd905f", + "version" : "6.13.2" + } + }, + { + "identity" : "asyncextensions", + "kind" : "remoteSourceControl", + "location" : "https://github.com/sideeffect-io/AsyncExtensions.git", + "state" : { + "revision" : "3442d3d046800f1974bda096faaf0ac510b21154", + "version" : "0.5.3" + } + }, + { + "identity" : "bigint", + "kind" : "remoteSourceControl", + "location" : "https://github.com/attaswift/BigInt", + "state" : { + "revision" : "0ed110f7555c34ff468e72e1686e59721f2b0da6", + "version" : "5.3.0" + } + }, + { + "identity" : "codescanner", + "kind" : "remoteSourceControl", + "location" : "https://github.com/twostraws/CodeScanner", + "state" : { + "revision" : "bf5d7087015620b250ee6c865b3c9039fc159d1a", + "version" : "2.3.3" + } + }, + { + "identity" : "collectionconcurrencykit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/JohnSundell/CollectionConcurrencyKit", + "state" : { + "revision" : "b4f23e24b5a1bff301efc5e70871083ca029ff95", + "version" : "0.2.0" + } + }, + { + "identity" : "combine-schedulers", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/combine-schedulers", + "state" : { + "revision" : "9dc9cbe4bc45c65164fa653a563d8d8db61b09bb", + "version" : "1.0.0" + } + }, + { + "identity" : "iossecuritysuite", + "kind" : "remoteSourceControl", + "location" : "https://github.com/securing/IOSSecuritySuite.git", + "state" : { + "revision" : "651f1ca002b1060214173e55b9040272ae91abcd", + "version" : "1.9.11" + } + }, + { + "identity" : "jsonpreview", + "kind" : "remoteSourceControl", + "location" : "https://github.com/rakuyoMo/JSONPreview", + "state" : { + "revision" : "49831cdc9c9e81f6d3bbe118dc6515a631be0d68", + "version" : "2.2.3" + } + }, + { + "identity" : "keychainaccess", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kishikawakatsumi/KeychainAccess", + "state" : { + "revision" : "84e546727d66f1adc5439debad16270d0fdd04e7", + "version" : "4.2.2" + } + }, + { + "identity" : "legibleerror", + "kind" : "remoteSourceControl", + "location" : "https://github.com/mxcl/LegibleError", + "state" : { + "revision" : "bc596702d7ff618c3f90ba480eeb48b3e83a2fbe", + "version" : "1.0.6" + } + }, + { + "identity" : "nuke", + "kind" : "remoteSourceControl", + "location" : "https://github.com/kean/Nuke", + "state" : { + "revision" : "33f7e93be5d4ec027d42af77a8ec4680d1862ad2", + "version" : "11.6.4" + } + }, + { + "identity" : "sargon", + "kind" : "remoteSourceControl", + "location" : "https://github.com/radixdlt/sargon/", + "state" : { + "revision" : "83e13eb11037733a9edfe2c2c70d1efeb63e0831", + "version" : "1.1.42" + } + }, + { + "identity" : "screenshotpreventing-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Sajjon/ScreenshotPreventing-iOS", + "state" : { + "revision" : "03769bcd1b1c9c24af424890f0a3e6d15bd3000c" + } + }, + { + "identity" : "swift-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-algorithms.git", + "state" : { + "revision" : "b14b7f4c528c942f121c8b860b9410b2bf57825e", + "version" : "1.0.0" + } + }, + { + "identity" : "swift-async-algorithms", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-async-algorithms.git", + "state" : { + "revision" : "9cfed92b026c524674ed869a4ff2dcfdeedf8a2a", + "version" : "0.1.0" + } + }, + { + "identity" : "swift-atomics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-atomics.git", + "state" : { + "revision" : "6c89474e62719ddcc1e9614989fff2f68208fe10", + "version" : "1.1.0" + } + }, + { + "identity" : "swift-builders", + "kind" : "remoteSourceControl", + "location" : "https://github.com/davdroman/swift-builders", + "state" : { + "revision" : "c2f1dc3ac3596732359926a5ef5e3ba7009aac21", + "version" : "0.6.0" + } + }, + { + "identity" : "swift-case-paths", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-case-paths", + "state" : { + "revision" : "e072139e13f2f3e582251b49835abcf3421ac69a", + "version" : "1.2.3" + } + }, + { + "identity" : "swift-clocks", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-clocks", + "state" : { + "revision" : "a8421d68068d8f45fbceb418fbf22c5dad4afd33", + "version" : "1.0.2" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections.git", + "state" : { + "revision" : "94cf62b3ba8d4bed62680a282d4c25f9c63c2efb", + "version" : "1.1.0" + } + }, + { + "identity" : "swift-composable-architecture", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-composable-architecture", + "state" : { + "revision" : "cf967a28a8605629559533320d604168d733fc9c", + "version" : "1.8.0" + } + }, + { + "identity" : "swift-concurrency-extras", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-concurrency-extras", + "state" : { + "revision" : "bb5059bde9022d69ac516803f4f227d8ac967f71", + "version" : "1.1.0" + } + }, + { + "identity" : "swift-custom-dump", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-custom-dump", + "state" : { + "revision" : "f01efb26f3a192a0e88dcdb7c3c391ec2fc25d9c", + "version" : "1.3.0" + } + }, + { + "identity" : "swift-dependencies", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-dependencies", + "state" : { + "revision" : "09e49dd46932adfe80ce672b4b3772d79ee6c21a", + "version" : "1.2.1" + } + }, + { + "identity" : "swift-dependencies-additions", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tgrapperon/swift-dependencies-additions", + "state" : { + "revision" : "02e7b1801a96828049fe4d3e8bdc5e608ef5ffbc", + "version" : "1.0.1" + } + }, + { + "identity" : "swift-either", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-either", + "state" : { + "branch" : "main", + "revision" : "db33f4084304e2ef47c8b4d2949f0eb286f95b90" + } + }, + { + "identity" : "swift-identified-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-identified-collections", + "state" : { + "revision" : "d533cd18b0b456b106694a9899f917ee595f2666", + "version" : "1.0.2" + } + }, + { + "identity" : "swift-json-testing", + "kind" : "remoteSourceControl", + "location" : "https://github.com/davdroman/swift-json-testing", + "state" : { + "revision" : "de48704db4af7d448bc27aea305b39494fed6eec", + "version" : "0.2.0" + } + }, + { + "identity" : "swift-log", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-log.git", + "state" : { + "revision" : "e97a6fcb1ab07462881ac165fdbb37f067e205d5", + "version" : "1.5.4" + } + }, + { + "identity" : "swift-log-console-colors", + "kind" : "remoteSourceControl", + "location" : "https://github.com/nneuberger1/swift-log-console-colors", + "state" : { + "revision" : "510bfc6ef5d656ea450497c4c2b50e0cd0240403", + "version" : "1.0.3" + } + }, + { + "identity" : "swift-log-file", + "kind" : "remoteSourceControl", + "location" : "https://github.com/crspybits/swift-log-file", + "state" : { + "revision" : "aa94b38bf88c7d9cbc87ceafcdffadaffbc2bffa", + "version" : "0.1.0" + } + }, + { + "identity" : "swift-nonempty", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-nonempty.git", + "state" : { + "revision" : "8074e5f2e4a6de5a42476e545cc33438021aa2a4", + "version" : "0.4.0" + } + }, + { + "identity" : "swift-numerics", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-numerics", + "state" : { + "revision" : "0a5bc04095a675662cf24757cc0640aa2204253b", + "version" : "1.0.2" + } + }, + { + "identity" : "swift-overture", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-overture.git", + "state" : { + "revision" : "7977acd7597f413717058acc1e080731249a1d7e", + "version" : "0.5.0" + } + }, + { + "identity" : "swift-perception", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-perception", + "state" : { + "revision" : "42240120b2a8797595433288ab4118f8042214c3", + "version" : "1.1.1" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax", + "state" : { + "revision" : "64889f0c732f210a935a0ad7cda38f77f876262d", + "version" : "509.1.1" + } + }, + { + "identity" : "swift-tagged", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-tagged.git", + "state" : { + "revision" : "3907a9438f5b57d317001dc99f3f11b46882272b", + "version" : "0.10.0" + } + }, + { + "identity" : "swift-validated", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swift-validated.git", + "state" : { + "revision" : "e9685ce68943c9e9d26f9f999c64823dea3ef0e7", + "version" : "0.2.1" + } + }, + { + "identity" : "swiftui-introspect", + "kind" : "remoteSourceControl", + "location" : "https://github.com/siteline/SwiftUI-Introspect", + "state" : { + "revision" : "3ba734dd20faada0e3234b68e78db97005315f0e", + "version" : "1.0.0" + } + }, + { + "identity" : "swiftui-navigation", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/swiftui-navigation.git", + "state" : { + "revision" : "d9e72f3083c08375794afa216fb2f89c0114f303", + "version" : "1.2.1" + } + }, + { + "identity" : "swiftui-navigation-transitions", + "kind" : "remoteSourceControl", + "location" : "https://github.com/davdroman/swiftui-navigation-transitions", + "state" : { + "revision" : "a6a3c70ad5d771bd1e927fb55897231cd9592024", + "version" : "0.13.3" + } + }, + { + "identity" : "swiftyjson", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SwiftyJSON/SwiftyJSON", + "state" : { + "revision" : "af76cf3ef710b6ca5f8c05f3a31307d44a3c5828", + "version" : "5.0.2" + } + }, + { + "identity" : "textbuilder", + "kind" : "remoteSourceControl", + "location" : "https://github.com/davdroman/TextBuilder", + "state" : { + "revision" : "65b7c7bb9b163f4fc2d755c52a89a6f3040300df", + "version" : "3.0.1" + } + }, + { + "identity" : "webrtc", + "kind" : "remoteSourceControl", + "location" : "https://github.com/stasel/WebRTC/", + "state" : { + "revision" : "cdf22dbb602fd268ab60fccc647d62892b8bb7ed", + "version" : "123.0.0" + } + }, + { + "identity" : "xcglogger", + "kind" : "remoteSourceControl", + "location" : "https://github.com/DaveWoodCom/XCGLogger.git", + "state" : { + "revision" : "a9c4667b247928a29bdd41be2ec2c8d304215a54", + "version" : "7.0.1" + } + }, + { + "identity" : "xctest-dynamic-overlay", + "kind" : "remoteSourceControl", + "location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", + "state" : { + "revision" : "6f30bdba373bbd7fbfe241dddd732651f2fbd1e2", + "version" : "1.1.2" + } + } + ], + "version" : 3 +} diff --git a/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Interface.swift b/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Interface.swift index 3bdb61a459..a70faad033 100644 --- a/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Interface.swift +++ b/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Interface.swift @@ -11,7 +11,7 @@ extension PreAuthorizationClient { // MARK: PreAuthorizationClient.GetPreviewRequest extension PreAuthorizationClient { struct GetPreviewRequest: Hashable, Sendable { - let unvalidatedManifest: UnvalidatedTransactionManifest + let unvalidatedManifest: UnvalidatedSubintentManifest let nonce: Nonce } } diff --git a/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Live.swift b/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Live.swift index 8428cf913c..69ed6aa822 100644 --- a/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Live.swift +++ b/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Live.swift @@ -6,7 +6,7 @@ extension PreAuthorizationClient: DependencyKey { func analysePreview(request: GetPreviewRequest) async throws -> PreAuthToReview { do { return try await SargonOS.shared.analysePreAuthPreview( - instructions: request.unvalidatedManifest.transactionManifestString, + instructions: request.unvalidatedManifest.subintentManifestString, blobs: request.unvalidatedManifest.blobs, nonce: request.nonce ) diff --git a/RadixWallet/Core/SharedModels/P2P/Dapp/Models/WalletInteraction+Extensions.swift b/RadixWallet/Core/SharedModels/P2P/Dapp/Models/WalletInteraction+Extensions.swift index 6664cafe1b..ff80d7fa53 100644 --- a/RadixWallet/Core/SharedModels/P2P/Dapp/Models/WalletInteraction+Extensions.swift +++ b/RadixWallet/Core/SharedModels/P2P/Dapp/Models/WalletInteraction+Extensions.swift @@ -43,7 +43,7 @@ extension DappToWalletInteractionSendTransactionItem { extension DappToWalletInteractionSubintentRequestItem { init( - unvalidatedManifest: UnvalidatedTransactionManifest, + unvalidatedManifest: UnvalidatedSubintentManifest, expiration: DappToWalletInteractionSubintentExpiration? = nil ) { self.init( diff --git a/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+Reducer.swift b/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+Reducer.swift index e54db75334..4d5ca8ca24 100644 --- a/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+Reducer.swift +++ b/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+Reducer.swift @@ -202,6 +202,7 @@ struct DevAccountPreferences: Sendable, FeatureReducer { } case .createPreAuthorizationButtonTapped: return .run { _ in + // TODO: Get Manifest from Sargon let manifest = """ CALL_METHOD Address("component_tdx_2_1cptxxxxxxxxxfaucetxxxxxxxxx000527798379xxxxxxxxxyulkzl") @@ -217,10 +218,10 @@ struct DevAccountPreferences: Sendable, FeatureReducer { YIELD_TO_PARENT; """ - let unvalidated = UnvalidatedTransactionManifest(transactionManifestString: manifest, blobs: Blobs([])) + let unvalidatedManifest = UnvalidatedSubintentManifest(subintentManifestString: manifest, blobs: Blobs([])) _ = await dappInteractionClient.addWalletInteraction( - .preAuthorization(.init(request: .init(unvalidatedManifest: unvalidated))), + .preAuthorization(.init(request: .init(unvalidatedManifest: unvalidatedManifest))), .accountTransfer ) } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 14d5680319..b1d01bc978 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -4,7 +4,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { typealias Expiration = DappToWalletInteractionSubintentExpiration struct State: Sendable, Hashable { - let unvalidatedManifest: UnvalidatedTransactionManifest + let unvalidatedManifest: UnvalidatedSubintentManifest let expiration: Expiration? let nonce: Nonce let signTransactionPurpose: SigningPurpose.SignTransactionPurpose From c78511773542dee6c54ad27d9442c1a137920986 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Wed, 30 Oct 2024 11:17:13 -0300 Subject: [PATCH 50/63] localise new views --- .../Sections/Sections+View.swift | 2 +- .../PreAuthorizationReview+View.swift | 38 ++++++++----------- .../PreAuthorizationReview.swift | 4 +- 3 files changed, 18 insertions(+), 26 deletions(-) diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift index 4b600a7b80..eb1df33a43 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift @@ -197,7 +197,7 @@ extension InteractionReview.Sections { .foregroundStyle(.app.gray3) .frame(.smallest) - Text("Possible dApp calls") + Text(L10n.InteractionReview.possibleDappCalls) .textStyle(.body2HighImportance) .foregroundStyle(.app.gray2) .padding(.leading, .small2) diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index 6b038d342e..b3c721d944 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -63,12 +63,12 @@ extension PreAuthorizationReview { private func navigationTitle(dAppName: String?) -> some SwiftUI.View { VStack(spacing: .zero) { - Text("Review your Pre-Authorization") + Text(L10n.PreAuthorizationReview.title) .textStyle(.body2Header) .foregroundColor(.app.gray1) if let dAppName { - Text("Proposed by \(dAppName)") + Text(L10n.PreAuthorizationReview.subtitle(dAppName)) .textStyle(.body2Regular) .foregroundColor(.app.gray2) } @@ -98,7 +98,7 @@ extension PreAuthorizationReview { expiration(viewStore.expiration, secondsToExpiration: viewStore.secondsToExpiration) ApprovalSlider( - title: "Slide to sign and return", + title: L10n.PreAuthorizationReview.slideToSign, resetDate: viewStore.sliderResetDate ) {} .controlState(viewStore.sliderControlState) @@ -164,10 +164,10 @@ extension PreAuthorizationReview { private func feesInformation(dAppName: String?) -> some SwiftUI.View { HStack(spacing: .zero) { VStack(alignment: .leading, spacing: .zero) { - Text("Pre-authorization will be returned to \(dAppName ?? "dApp") for processing.") + Text(L10n.PreAuthorizationReview.Fees.title(dAppName ?? "dApp")) .foregroundStyle(.app.gray1) - Text("Network fees will be paid by the dApp") + Text(L10n.PreAuthorizationReview.Fees.subtitle) .foregroundStyle(.app.gray2) } .lineSpacing(0) @@ -191,15 +191,15 @@ extension PreAuthorizationReview { if let seconds = secondsToExpiration { if seconds > 0 { let value = formatTime(seconds: seconds) - Text("Valid for the next **\(value)**") + Text(markdown: L10n.PreAuthorizationReview.Expiration.atTime(value), emphasizedColor: .app.account4pink, emphasizedFont: .app.body2Link) } else { - Text("This PreAuthorization is no longer valid") + Text(L10n.PreAuthorizationReview.Expiration.expired) } } case let .afterDelay(value): let value = formatTime(seconds: Int(value.expireAfterSeconds)) - Text("Valid for **\(value) after approval**") + Text(markdown: L10n.PreAuthorizationReview.Expiration.afterDelay(value), emphasizedColor: .app.account4pink, emphasizedFont: .app.body2Link) case nil: Color.clear @@ -221,28 +221,29 @@ private extension PreAuthorizationReview.View { /// - `56:02 minutes` / `1:23 minute` /// - `34 seconds` / `1 second` func formatTime(seconds: Int) -> String { + typealias S = L10n.PreAuthorizationReview.TimeFormat let minutes = seconds / 60 let hours = minutes / 60 let days = hours / 24 if days > 0 { - return days == 1 ? "1 day" : "\(days) days" + return days == 1 ? S.day : S.days(days) } else if hours > 0 { let remainingMinutes = minutes % 60 let formatted = String(format: "%d:%02d", hours, remainingMinutes) - return hours == 1 ? "\(formatted) hour" : "\(formatted) hours" + return hours == 1 ? S.hour(formatted) : S.hours(formatted) } else if minutes > 0 { let remainingSeconds = seconds % 60 let formatted = String(format: "%d:%02d", minutes, remainingSeconds) - return minutes == 1 ? "\(formatted) minute" : "\(formatted) minutes" + return minutes == 1 ? S.minute(formatted) : S.minutes(formatted) } else { - return seconds == 1 ? "1 second" : "\(seconds) seconds" + return seconds == 1 ? S.second : S.seconds(seconds) } } } private extension PreAuthorizationReview.State { var globalControlState: ControlState { - reviewedPreAuthorization != nil ? .enabled : .loading(.global(text: "Incoming PreAuthorization")) + reviewedPreAuthorization != nil ? .enabled : .loading(.global(text: L10n.PreAuthorizationReview.loading)) } var sliderControlState: ControlState { @@ -254,19 +255,10 @@ private extension PreAuthorizationReview.State { } } -extension StoreOf { - var destination: PresentationStoreOf { - func scopeState(state: State) -> PresentationState { - state.$destination - } - return scope(state: scopeState, action: Action.destination) - } -} - @MainActor private extension View { func destinations(with store: StoreOf) -> some View { - let destinationStore = store.destination + let destinationStore = store.scope(state: \.$destination, action: \.destination) return rawManifestAlert(with: destinationStore) } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index b1d01bc978..70bf337b99 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -213,11 +213,11 @@ extension PreAuthorizationReview.State { private extension AlertState { static var rawManifest: AlertState { AlertState { - TextState("Warning") + TextState(L10n.PreAuthorizationReview.RawManifestAlert.title) } actions: { .default(TextState(L10n.Common.continue)) } message: { - TextState("This is a complex pre-authorization that cannot be summarized - the raw pre-authorization manifest will be shown. Do not sign and return unless you understand the contents.") + TextState(L10n.PreAuthorizationReview.RawManifestAlert.message) } } } From 7ccad4b04c4cef52b8c2bd8d4d080f1c808fe2fc Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Wed, 30 Oct 2024 11:45:56 -0300 Subject: [PATCH 51/63] use new Localization strings on common views --- .../SecureStorageClient+Live.swift | 4 ++-- .../AccountCard/AccountCard+DataSource.swift | 2 +- .../ResourceBalance/ResourceBalanceView.swift | 8 +++---- .../DerivePublicKeys/DerivePublicKeys.swift | 4 ++-- .../Components/HeadingView.swift | 22 +++++++++---------- .../Sections/Accounts/Accounts+View.swift | 4 ++-- .../DepositExceptionsView.swift | 10 ++++----- .../DepositSetting/DepositSettingView.swift | 6 ++--- .../Sections/Proofs/Proofs+View.swift | 2 +- 9 files changed, 31 insertions(+), 31 deletions(-) diff --git a/RadixWallet/Clients/SecureStorageClient/SecureStorageClient+Live.swift b/RadixWallet/Clients/SecureStorageClient/SecureStorageClient+Live.swift index 79d912e3db..2143d14f27 100644 --- a/RadixWallet/Clients/SecureStorageClient/SecureStorageClient+Live.swift +++ b/RadixWallet/Clients/SecureStorageClient/SecureStorageClient+Live.swift @@ -515,8 +515,8 @@ private func key(factorSourceID: FactorSourceIDFromHash) -> KeychainClient.Key { extension OverlayWindowClient.Item.AlertState { fileprivate static let missingMnemonicAlert = Self( - title: { TextState(L10n.TransactionReview.NoMnemonicError.title) }, - message: { TextState(L10n.TransactionReview.NoMnemonicError.text) } + title: { TextState(L10n.Common.NoMnemonicAlert.title) }, + message: { TextState(L10n.Common.NoMnemonicAlert.text) } ) } diff --git a/RadixWallet/Core/FeaturePrelude/AccountCard/AccountCard+DataSource.swift b/RadixWallet/Core/FeaturePrelude/AccountCard/AccountCard+DataSource.swift index 975239527a..047b45012b 100644 --- a/RadixWallet/Core/FeaturePrelude/AccountCard/AccountCard+DataSource.swift +++ b/RadixWallet/Core/FeaturePrelude/AccountCard/AccountCard+DataSource.swift @@ -98,7 +98,7 @@ private extension AccountForDisplay { private extension AccountAddress { var asDataSource: AccountCardDataSource { - .init(title: L10n.TransactionReview.externalAccountName, ledgerIdentifiable: .address(.account(self)), gradient: .external) + .init(title: L10n.InteractionReview.externalAccountName, ledgerIdentifiable: .address(.account(self)), gradient: .external) } } diff --git a/RadixWallet/Features/AssetsFeature/Components/HelperViews/ResourceBalance/ResourceBalanceView.swift b/RadixWallet/Features/AssetsFeature/Components/HelperViews/ResourceBalance/ResourceBalanceView.swift index 9b496ec2df..444c513999 100644 --- a/RadixWallet/Features/AssetsFeature/Components/HelperViews/ResourceBalance/ResourceBalanceView.swift +++ b/RadixWallet/Features/AssetsFeature/Components/HelperViews/ResourceBalance/ResourceBalanceView.swift @@ -283,7 +283,7 @@ extension ResourceBalanceView { .padding(.horizontal, hideDetails ? .zero : .small3) if !hideDetails { - Text(L10n.TransactionReview.worth.uppercased()) + Text(L10n.InteractionReview.worth.uppercased()) .textStyle(.body2HighImportance) .foregroundColor(.app.gray2) .padding(.top, .small2) @@ -581,7 +581,7 @@ extension ResourceBalanceView { } else { VStack(alignment: .trailing, spacing: 0) { if amount.guaranteed != nil { - Text(L10n.TransactionReview.estimated) + Text(L10n.InteractionReview.estimated) .textStyle(.body2HighImportance) .foregroundColor(.app.gray1) } @@ -600,7 +600,7 @@ extension ResourceBalanceView { } if let guaranteedAmount = amount.guaranteed { - Text(L10n.TransactionReview.guaranteed) + Text(L10n.InteractionReview.guaranteed) .textStyle(.body2HighImportance) .foregroundColor(.app.gray2) .padding(.top, .small3) @@ -627,7 +627,7 @@ extension ResourceBalanceView.StakeClaimNFT.Tokens.SectionKind { case .readyToBeClaimed: L10n.Account.Staking.readyToBeClaimed case .toBeClaimed: - L10n.TransactionReview.toBeClaimed + L10n.InteractionReview.toBeClaimed } } } diff --git a/RadixWallet/Features/DerivePublicKeys/DerivePublicKeys.swift b/RadixWallet/Features/DerivePublicKeys/DerivePublicKeys.swift index 0c8f8d6431..2538fe0150 100644 --- a/RadixWallet/Features/DerivePublicKeys/DerivePublicKeys.swift +++ b/RadixWallet/Features/DerivePublicKeys/DerivePublicKeys.swift @@ -491,7 +491,7 @@ extension SLIP10Curve { private extension AlertState { static let failedToFindFactorSourceAlert: AlertState = .init( title: { - TextState(L10n.TransactionReview.NoMnemonicError.title) + TextState(L10n.Common.NoMnemonicAlert.title) }, actions: { ButtonState(action: .ok) { @@ -499,7 +499,7 @@ private extension AlertState { } }, message: { - TextState(L10n.TransactionReview.NoMnemonicError.text) + TextState(L10n.Common.NoMnemonicAlert.text) } ) } diff --git a/RadixWallet/Features/InteractionReview/Components/HeadingView.swift b/RadixWallet/Features/InteractionReview/Components/HeadingView.swift index af6916236f..099798c6c7 100644 --- a/RadixWallet/Features/InteractionReview/Components/HeadingView.swift +++ b/RadixWallet/Features/InteractionReview/Components/HeadingView.swift @@ -30,57 +30,57 @@ extension InteractionReview { } static let message = HeadingView( - L10n.TransactionReview.messageHeading, + L10n.InteractionReview.messageHeading, icon: AssetResource.transactionReviewMessage ) static let withdrawing = HeadingView( - L10n.TransactionReview.withdrawalsHeading, + L10n.InteractionReview.withdrawalsHeading, icon: AssetResource.transactionReviewWithdrawing ) static let depositing = HeadingView( - L10n.TransactionReview.depositsHeading, + L10n.InteractionReview.depositsHeading, icon: AssetResource.transactionReviewDepositing ) static let usingDapps = HeadingView( - L10n.TransactionReview.usingDappsHeading, + L10n.InteractionReview.usingDappsHeading, icon: AssetResource.transactionReviewDapps ) static let contributingToPools = HeadingView( - L10n.TransactionReview.poolContributionHeading, + L10n.InteractionReview.poolContributionHeading, icon: AssetResource.transactionReviewPools ) static let redeemingFromPools = HeadingView( - L10n.TransactionReview.poolRedemptionHeading, + L10n.InteractionReview.poolRedemptionHeading, icon: AssetResource.transactionReviewPools ) static let stakingToValidators = HeadingView( - L10n.TransactionReview.stakingToValidatorsHeading, + L10n.InteractionReview.stakingToValidatorsHeading, icon: AssetResource.iconValidator ) static let unstakingFromValidators = HeadingView( - L10n.TransactionReview.unstakingFromValidatorsHeading, + L10n.InteractionReview.unstakingFromValidatorsHeading, icon: AssetResource.iconValidator ) static let claimingFromValidators = HeadingView( - L10n.TransactionReview.claimFromValidatorsHeading, + L10n.InteractionReview.claimFromValidatorsHeading, icon: AssetResource.iconValidator ) static let depositSetting = HeadingView( - L10n.TransactionReview.thirdPartyDepositSettingHeading, + L10n.InteractionReview.thirdPartyDepositSettingHeading, icon: AssetResource.transactionReviewDepositSetting ) static let depositExceptions = HeadingView( - L10n.TransactionReview.thirdPartyDepositExceptionsHeading, + L10n.InteractionReview.thirdPartyDepositExceptionsHeading, icon: AssetResource.transactionReviewDepositSetting ) } diff --git a/RadixWallet/Features/InteractionReview/Sections/Accounts/Accounts+View.swift b/RadixWallet/Features/InteractionReview/Sections/Accounts/Accounts+View.swift index 52b461852b..e4d198447f 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Accounts/Accounts+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Accounts/Accounts+View.swift @@ -16,7 +16,7 @@ extension InteractionReview.Accounts { ) if store.enableCustomizeGuarantees { - Button(L10n.TransactionReview.customizeGuaranteesButtonTitle) { + Button(L10n.InteractionReview.customizeGuaranteesButtonTitle) { store.send(.view(.customizeGuaranteesTapped)) } .textStyle(.body1Header) @@ -85,7 +85,7 @@ struct TransactionReviewResourceView: View { guard let isHidden = transfer.isHidden, isHidden else { return nil } - return isDeposit ? L10n.TransactionReview.HiddenAsset.deposit : L10n.TransactionReview.HiddenAsset.withdraw + return isDeposit ? L10n.InteractionReview.HiddenAsset.deposit : L10n.InteractionReview.HiddenAsset.withdraw } } diff --git a/RadixWallet/Features/InteractionReview/Sections/DepositExceptions/DepositExceptionsView.swift b/RadixWallet/Features/InteractionReview/Sections/DepositExceptions/DepositExceptionsView.swift index 9346b7ad0f..8d32a4db00 100644 --- a/RadixWallet/Features/InteractionReview/Sections/DepositExceptions/DepositExceptionsView.swift +++ b/RadixWallet/Features/InteractionReview/Sections/DepositExceptions/DepositExceptionsView.swift @@ -116,11 +116,11 @@ extension ResourcePreferenceUpdate { var text: String { switch self { case .set(.allowed): - L10n.TransactionReview.AccountDepositSettings.assetChangeAllow + L10n.InteractionReview.DepositExceptions.assetChangeAllow case .set(.disallowed): - L10n.TransactionReview.AccountDepositSettings.assetChangeDisallow + L10n.InteractionReview.DepositExceptions.assetChangeDisallow case .remove: - L10n.TransactionReview.AccountDepositSettings.assetChangeClear + L10n.InteractionReview.DepositExceptions.assetChangeClear } } } @@ -138,9 +138,9 @@ extension InteractionReview.DepositExceptionsChange.AllowedDepositorChange.Chang var text: String { switch self { case .added: - L10n.TransactionReview.AccountDepositSettings.depositorChangeAdd + L10n.InteractionReview.DepositExceptions.depositorChangeAdd case .removed: - L10n.TransactionReview.AccountDepositSettings.depositorChangeRemove + L10n.InteractionReview.DepositExceptions.depositorChangeRemove } } } diff --git a/RadixWallet/Features/InteractionReview/Sections/DepositSetting/DepositSettingView.swift b/RadixWallet/Features/InteractionReview/Sections/DepositSetting/DepositSettingView.swift index a002683aa4..ddc51d2111 100644 --- a/RadixWallet/Features/InteractionReview/Sections/DepositSetting/DepositSettingView.swift +++ b/RadixWallet/Features/InteractionReview/Sections/DepositSetting/DepositSettingView.swift @@ -63,11 +63,11 @@ extension AccountDefaultDepositRule { var string: String { switch self { case .acceptAll: - L10n.TransactionReview.AccountDepositSettings.acceptAllRule + L10n.InteractionReview.DepositSettings.acceptAllRule case .denyAll: - L10n.TransactionReview.AccountDepositSettings.denyAllRule + L10n.InteractionReview.DepositSettings.denyAllRule case .acceptKnown: - L10n.TransactionReview.AccountDepositSettings.acceptKnownRule + L10n.InteractionReview.DepositSettings.acceptKnownRule } } diff --git a/RadixWallet/Features/InteractionReview/Sections/Proofs/Proofs+View.swift b/RadixWallet/Features/InteractionReview/Sections/Proofs/Proofs+View.swift index 02fa22af68..0983aba610 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Proofs/Proofs+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Proofs/Proofs+View.swift @@ -10,7 +10,7 @@ extension InteractionReview.Proofs { WithPerceptionTracking { VStack(alignment: .leading, spacing: .medium2) { HStack { - Text(L10n.TransactionReview.presentingHeading) + Text(L10n.InteractionReview.presentingHeading) .sectionHeading .textCase(.uppercase) From b671c5f05ff3b4a54dde97cfc627fac40a491cea Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Wed, 30 Oct 2024 12:06:31 -0300 Subject: [PATCH 52/63] show possible dApp calls only for open manifests --- .../InteractionReview/Sections/Sections+View.swift | 10 ---------- .../Features/InteractionReview/Sections/Sections.swift | 9 ++++++--- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift index eb1df33a43..b414fd9d7c 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections+View.swift @@ -238,16 +238,6 @@ extension InteractionReview.Sections.State { var showTransferLine: Bool { withdrawals != nil && deposits != nil } - - var showPossibleDappCalls: Bool { - switch kind { - case .transaction: - false - case .preAuthorization: - // TODO: Only show for open pre authorizations - true - } - } } extension StoreOf { diff --git a/RadixWallet/Features/InteractionReview/Sections/Sections.swift b/RadixWallet/Features/InteractionReview/Sections/Sections.swift index ce13419894..2e36698537 100644 --- a/RadixWallet/Features/InteractionReview/Sections/Sections.swift +++ b/RadixWallet/Features/InteractionReview/Sections/Sections.swift @@ -23,6 +23,8 @@ extension InteractionReview { // The proofs are set here (within the resolve logic) but may be rendered and handled by the parent view, in the case they are placed outside the Sections (TransactionReview). var proofs: Proofs.State? = nil + var showPossibleDappCalls = false + @PresentationState var destination: Destination.State? = nil } @@ -189,7 +191,7 @@ extension InteractionReview { func reduce(into state: inout State, parentAction: InternalAction.ParentAction) -> Effect { switch parentAction { case let .resolveExecutionSummary(executionSummary, networkID): - .run { send in + return .run { send in let sections = try await sections(for: executionSummary, networkID: networkID) await send(.internal(.setSections(sections))) } catch: { error, send in @@ -198,7 +200,8 @@ extension InteractionReview { } case let .resolveManifestSummary(manifestSummary, networkID): - .run { send in + state.showPossibleDappCalls = true + return .run { send in let sections = try await sections(for: manifestSummary, networkID: networkID) await send(.internal(.setSections(sections))) } catch: { error, send in @@ -207,7 +210,7 @@ extension InteractionReview { } case let .showResourceDetails(resource, details): - resourceDetailsEffect(state: &state, resource: resource, details: details) + return resourceDetailsEffect(state: &state, resource: resource, details: details) } } From 0a57abecdf4cc4e12171a7a1ab29d7934523317f Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Wed, 30 Oct 2024 14:01:15 -0300 Subject: [PATCH 53/63] remove ReviewPreAuthorization and PreAuthorizationToReview, and instead use PreAuthorizationPreview --- .../Models/PreAuthorizationModels.swift | 2 +- .../PreAuthorizationClient+Interface.swift | 2 +- .../PreAuthorizationClient+Live.swift | 2 +- .../Coordinator/DappInteractionFlow.swift | 1 - .../PreAuthorizationReview+View.swift | 2 +- .../PreAuthorizationReview.swift | 20 ++++++++----------- 6 files changed, 12 insertions(+), 17 deletions(-) diff --git a/RadixWallet/Clients/PreAuthorizationClient/Models/PreAuthorizationModels.swift b/RadixWallet/Clients/PreAuthorizationClient/Models/PreAuthorizationModels.swift index 6648243cac..e600896595 100644 --- a/RadixWallet/Clients/PreAuthorizationClient/Models/PreAuthorizationModels.swift +++ b/RadixWallet/Clients/PreAuthorizationClient/Models/PreAuthorizationModels.swift @@ -1,6 +1,6 @@ import Foundation -struct PreAuthorizationToReview: Sendable, Hashable { +struct PreAuthorizationPreview: Sendable, Hashable { let kind: PreAuthToReview let networkID: NetworkID diff --git a/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Interface.swift b/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Interface.swift index a70faad033..d8e027c861 100644 --- a/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Interface.swift +++ b/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Interface.swift @@ -5,7 +5,7 @@ struct PreAuthorizationClient: Sendable { // MARK: PreAuthorizationClient.GetPreview extension PreAuthorizationClient { - typealias GetPreview = @Sendable (GetPreviewRequest) async throws -> PreAuthorizationToReview + typealias GetPreview = @Sendable (GetPreviewRequest) async throws -> PreAuthorizationPreview } // MARK: PreAuthorizationClient.GetPreviewRequest diff --git a/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Live.swift b/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Live.swift index 69ed6aa822..74b722698e 100644 --- a/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Live.swift +++ b/RadixWallet/Clients/PreAuthorizationClient/PreAuthorizationClient+Live.swift @@ -19,7 +19,7 @@ extension PreAuthorizationClient: DependencyKey { let kind = try await analysePreview(request: request) let networkID = await gatewaysClient.getCurrentNetworkID() - return PreAuthorizationToReview( + return PreAuthorizationPreview( kind: kind, networkID: networkID ) diff --git a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift index 4aa74ebac3..0747a961a6 100644 --- a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift +++ b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift @@ -1042,7 +1042,6 @@ extension DappInteractionFlow.Path.State { unvalidatedManifest: item.unvalidatedManifest, expiration: item.expiration, nonce: .secureRandom(), - signTransactionPurpose: .manifestFromDapp, dAppMetadata: dappMetadata.onLedger )) } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index b3c721d944..0c9a273099 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -243,7 +243,7 @@ private extension PreAuthorizationReview.View { private extension PreAuthorizationReview.State { var globalControlState: ControlState { - reviewedPreAuthorization != nil ? .enabled : .loading(.global(text: L10n.PreAuthorizationReview.loading)) + preview != nil ? .enabled : .loading(.global(text: L10n.PreAuthorizationReview.loading)) } var sliderControlState: ControlState { diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index 70bf337b99..ae7d6d1477 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -7,10 +7,9 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { let unvalidatedManifest: UnvalidatedSubintentManifest let expiration: Expiration? let nonce: Nonce - let signTransactionPurpose: SigningPurpose.SignTransactionPurpose let dAppMetadata: DappMetadata.Ledger? - var reviewedPreAuthorization: ReviewedPreAuthorization? + var preview: PreAuthorizationPreview? var displayMode: Common.DisplayMode = .detailed var sliderResetDate: Date = .now // TODO: reset when it corresponds @@ -35,7 +34,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { } enum InternalAction: Sendable, Equatable { - case previewLoaded(TaskResult) + case previewLoaded(TaskResult) case updateSecondsToExpiration(Date) } @@ -124,7 +123,7 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { return .send(.delegate(.failed(failure))) case let .previewLoaded(.success(preview)): - state.reviewedPreAuthorization = .init(manifest: preview.manifest) + state.preview = preview var effects: [Effect] = [] @@ -178,25 +177,22 @@ private extension PreAuthorizationReview { } func showRawManifest(_ state: inout State) -> Effect { - guard let reviewedPreAuthorization = state.reviewedPreAuthorization else { - struct MissingReviewedPreAuthorization: Error {} - errorQueue.schedule(MissingReviewedPreAuthorization()) + guard let preview = state.preview else { + struct MissingPreAuthorizationPreview: Error {} + errorQueue.schedule(MissingPreAuthorizationPreview()) return .none } - state.displayMode = .raw(reviewedPreAuthorization.manifest.manifestString) + state.displayMode = .raw(preview.manifest.manifestString) return .none } } +// MARK: PreAuthorizationReview.CancellableId extension PreAuthorizationReview { private enum CancellableId: Hashable { case expirationTimer } - - struct ReviewedPreAuthorization: Sendable, Hashable { - let manifest: SubintentManifest - } } extension PreAuthorizationReview.State { From 5776e0becd08b41631b98b666bc91f14751088ac Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 4 Nov 2024 11:41:16 +0100 Subject: [PATCH 54/63] fix info link --- .../Features/AppFeature/Overlay/InfoLinkSheet+Reducer.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RadixWallet/Features/AppFeature/Overlay/InfoLinkSheet+Reducer.swift b/RadixWallet/Features/AppFeature/Overlay/InfoLinkSheet+Reducer.swift index 55a63a1497..9afb6c6e54 100644 --- a/RadixWallet/Features/AppFeature/Overlay/InfoLinkSheet+Reducer.swift +++ b/RadixWallet/Features/AppFeature/Overlay/InfoLinkSheet+Reducer.swift @@ -156,9 +156,9 @@ extension InfoLinkSheet.GlossaryItem { case .payingaccount: L10n.InfoLink.Glossary.payingaccount case .preauthorizations: - "L10n.InfoLink.Glossary.preauthorizations" + L10n.InfoLink.Glossary.preauthorizations case .possibledappcalls: - "L10n.InfoLink.Glossary.possibledappcalls" + L10n.InfoLink.Glossary.possibledappcalls } } } From 29b100b6bba1a4eb987b7abae63617de3a7245d6 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 4 Nov 2024 14:53:49 +0100 Subject: [PATCH 55/63] test directly with dApp --- .../DevAccountPreferences+Reducer.swift | 27 ------------------- .../Children/DevAccountPreferences+View.swift | 4 --- 2 files changed, 31 deletions(-) diff --git a/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+Reducer.swift b/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+Reducer.swift index 4d5ca8ca24..1dd957256e 100644 --- a/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+Reducer.swift +++ b/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+Reducer.swift @@ -49,7 +49,6 @@ struct DevAccountPreferences: Sendable, FeatureReducer { case createNonFungibleTokenButtonTapped case createMultipleFungibleTokenButtonTapped case createMultipleNonFungibleTokenButtonTapped - case createPreAuthorizationButtonTapped case deleteAccountButtonTapped #endif // DEBUG } @@ -97,7 +96,6 @@ struct DevAccountPreferences: Sendable, FeatureReducer { @Dependency(\.accountsClient) var accountsClient @Dependency(\.errorQueue) var errorQueue - @Dependency(\.dappInteractionClient) var dappInteractionClient #if DEBUG @Dependency(\.gatewayAPIClient) var gatewayAPIClient @@ -200,31 +198,6 @@ struct DevAccountPreferences: Sendable, FeatureReducer { } catch: { error, _ in loggerGlobal.warning("Failed to create manifest which turns account into dapp definition account type, error: \(error)") } - case .createPreAuthorizationButtonTapped: - return .run { _ in - // TODO: Get Manifest from Sargon - let manifest = """ - CALL_METHOD - Address("component_tdx_2_1cptxxxxxxxxxfaucetxxxxxxxxx000527798379xxxxxxxxxyulkzl") - "free" - ; - - CALL_METHOD - Address("account_tdx_2_1299trm47s3x648jemhu3lfm4d6gt73289rd9s2hpdjm3tp5pdwq4m5") - "try_deposit_batch_or_abort" - Expression("ENTIRE_WORKTOP") - Enum<0u8>() - ; - - YIELD_TO_PARENT; - """ - let unvalidatedManifest = UnvalidatedSubintentManifest(subintentManifestString: manifest, blobs: Blobs([])) - - _ = await dappInteractionClient.addWalletInteraction( - .preAuthorization(.init(request: .init(unvalidatedManifest: unvalidatedManifest))), - .accountTransfer - ) - } #endif } diff --git a/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+View.swift b/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+View.swift index 2a37f25050..26bd98b8a1 100644 --- a/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+View.swift +++ b/RadixWallet/Features/AccountPreferencesFeature/Children/DevAccountPreferences+View.swift @@ -72,10 +72,6 @@ extension DevAccountPreferences { createNonFungibleTokenButton(with: viewStore) createMultipleFungibleTokenButton(with: viewStore) createMultipleNonFungibleTokenButton(with: viewStore) - Button("Create PreAuthorization") { - viewStore.send(.createPreAuthorizationButtonTapped) - } - .buttonStyle(.secondaryRectangular(shouldExpand: true)) Spacer(minLength: 0) deleteAccountButton { store.send(.view(.deleteAccountButtonTapped)) } #endif // DEBUG From 9cdf6db8a966fe4fcf6bde4bc748540f97f4c963 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 4 Nov 2024 19:14:30 +0100 Subject: [PATCH 56/63] updates --- .../Dapp/Models/WalletInteraction+Extensions.swift | 14 -------------- .../InteractionReview/Components/HeaderView.swift | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/RadixWallet/Core/SharedModels/P2P/Dapp/Models/WalletInteraction+Extensions.swift b/RadixWallet/Core/SharedModels/P2P/Dapp/Models/WalletInteraction+Extensions.swift index ff80d7fa53..d6e43a0dfa 100644 --- a/RadixWallet/Core/SharedModels/P2P/Dapp/Models/WalletInteraction+Extensions.swift +++ b/RadixWallet/Core/SharedModels/P2P/Dapp/Models/WalletInteraction+Extensions.swift @@ -41,20 +41,6 @@ extension DappToWalletInteractionSendTransactionItem { } } -extension DappToWalletInteractionSubintentRequestItem { - init( - unvalidatedManifest: UnvalidatedSubintentManifest, - expiration: DappToWalletInteractionSubintentExpiration? = nil - ) { - self.init( - version: .default, - unvalidatedManifest: unvalidatedManifest, - message: nil, - expiration: expiration - ) - } -} - // MARK: - DappToWalletInteraction.RequestValidation extension DappToWalletInteraction { struct RequestValidation: Sendable, Hashable { diff --git a/RadixWallet/Features/InteractionReview/Components/HeaderView.swift b/RadixWallet/Features/InteractionReview/Components/HeaderView.swift index 1787dbb5ff..dce8178d46 100644 --- a/RadixWallet/Features/InteractionReview/Components/HeaderView.swift +++ b/RadixWallet/Features/InteractionReview/Components/HeaderView.swift @@ -43,7 +43,7 @@ extension InteractionReview { case .transaction: return L10n.TransactionReview.proposingDappSubtitle(name) case .preAuthorization: - return "Proposed by \(name)" + return L10n.PreAuthorizationReview.subtitle(name) } } From 0be24a389c9582c057ae25b8a4b4ae1c3c3ea63b Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 4 Nov 2024 21:11:29 +0100 Subject: [PATCH 57/63] VisibleHeaderView --- RadixWallet.xcodeproj/project.pbxproj | 4 + .../Components/VisibleHeaderView.swift | 96 +++++++++++++++++++ .../Helpers/InteractionReview+Extra.swift | 2 + .../PreAuthorizationReview+View.swift | 57 +---------- .../TransactionReview+View.swift | 58 +---------- 5 files changed, 107 insertions(+), 110 deletions(-) create mode 100644 RadixWallet/Features/InteractionReview/Components/VisibleHeaderView.swift diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index 159346b1ce..89667af2de 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -783,6 +783,7 @@ 5B8433A62CD011DE00CA00F5 /* PreAuthorizationClient+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8433A52CD011DC00CA00F5 /* PreAuthorizationClient+Test.swift */; }; 5B8433A82CD0128000CA00F5 /* PreAuthorizationClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8433A72CD0127900CA00F5 /* PreAuthorizationClient+Live.swift */; }; 5B8433AA2CD0131B00CA00F5 /* PreAuthorizationFailure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8433A92CD0131500CA00F5 /* PreAuthorizationFailure.swift */; }; + 5B8F770B2CD94CAD00154A76 /* VisibleHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F770A2CD94CA900154A76 /* VisibleHeaderView.swift */; }; 5B96DD372BD917B300722882 /* Text+Extra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B96DD362BD917B300722882 /* Text+Extra.swift */; }; 5B9846BD2BBD5C8800E814F3 /* SensitiveInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5B9846BC2BBD5C8800E814F3 /* SensitiveInfo.plist */; }; 5B9846C02BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9846BF2BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift */; }; @@ -2020,6 +2021,7 @@ 5B8433A52CD011DC00CA00F5 /* PreAuthorizationClient+Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationClient+Test.swift"; sourceTree = ""; }; 5B8433A72CD0127900CA00F5 /* PreAuthorizationClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationClient+Live.swift"; sourceTree = ""; }; 5B8433A92CD0131500CA00F5 /* PreAuthorizationFailure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreAuthorizationFailure.swift; sourceTree = ""; }; + 5B8F770A2CD94CA900154A76 /* VisibleHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleHeaderView.swift; sourceTree = ""; }; 5B96DD362BD917B300722882 /* Text+Extra.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Text+Extra.swift"; sourceTree = ""; }; 5B9846BC2BBD5C8800E814F3 /* SensitiveInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = SensitiveInfo.plist; sourceTree = ""; }; 5B9846BF2BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SensitiveInfoClient+Interface.swift"; sourceTree = ""; }; @@ -5539,6 +5541,7 @@ 5B27FBE82CC70AC2002975BE /* Components */ = { isa = PBXGroup; children = ( + 5B8F770A2CD94CA900154A76 /* VisibleHeaderView.swift */, 5B27FBD82CC67655002975BE /* HeadingView.swift */, 5B27FBEB2CC70E87002975BE /* ExpandableHeadingView.swift */, 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */, @@ -7594,6 +7597,7 @@ 48CFC4042ADC10D900E77A5C /* KeychainHolder.swift in Sources */, 48CFC4392ADC10DA00E77A5C /* Sorted.swift in Sources */, 5B272DD92C36E93100B74F1F /* AppEventsClient+Live.swift in Sources */, + 5B8F770B2CD94CAD00154A76 /* VisibleHeaderView.swift in Sources */, 48CFC34B2ADC10D900E77A5C /* OneTimePersonaData.swift in Sources */, A408159A2C7E0D08005E65B9 /* MetadataOriginArrayValue.swift in Sources */, 48CFC3832ADC10D900E77A5C /* GeneralHelperViews.swift in Sources */, diff --git a/RadixWallet/Features/InteractionReview/Components/VisibleHeaderView.swift b/RadixWallet/Features/InteractionReview/Components/VisibleHeaderView.swift new file mode 100644 index 0000000000..4fe61aa7f2 --- /dev/null +++ b/RadixWallet/Features/InteractionReview/Components/VisibleHeaderView.swift @@ -0,0 +1,96 @@ +import SwiftUI + +extension InteractionReview { + struct VisibleHeaderView: SwiftUI.View { + let kind: InteractionReview.Kind + let metadata: DappMetadata.Ledger? + let content: Content + + init( + kind: InteractionReview.Kind, + metadata: DappMetadata.Ledger?, + @ViewBuilder content: () -> Content + ) { + self.kind = kind + self.metadata = metadata + self.content = content() + } + + @SwiftUI.State private var showNavigationTitle = false + + private let coordSpace: String = "InteractionReviewCoordSpace" + private let navTitleID: String = "InteractionReview.title" + private let showTitleHysteresis: CGFloat = .small3 + + var body: some View { + ScrollView(showsIndicators: false) { + VStack(spacing: .zero) { + header + + content + } + } + .coordinateSpace(name: coordSpace) + .onPreferenceChange(PositionsPreferenceKey.self) { positions in + guard let offset = positions[navTitleID]?.maxY else { + showNavigationTitle = true + return + } + if showNavigationTitle, offset > showTitleHysteresis { + showNavigationTitle = false + } else if !showNavigationTitle, offset < 0 { + showNavigationTitle = true + } + } + .toolbar { + ToolbarItem(placement: .principal) { + if showNavigationTitle { + navigationTitle + } + } + } + } + + private var header: some SwiftUI.View { + Common.HeaderView( + kind: kind, + name: metadata?.name?.rawValue, + thumbnail: metadata?.thumbnail + ) + .measurePosition(navTitleID, coordSpace: coordSpace) + .padding(.horizontal, .medium3) + .padding(.bottom, .medium3) + .background { + switch kind { + case .transaction: + JaggedEdge(shadowColor: InteractionReview.shadowColor, isTopEdge: true) + case .preAuthorization: + EmptyView() + } + } + } + + private var navigationTitle: some SwiftUI.View { + VStack(spacing: .zero) { + Text(title) + .textStyle(.body2Header) + .foregroundColor(.app.gray1) + + if let dAppName = metadata?.name?.rawValue { + Text(L10n.PreAuthorizationReview.subtitle(dAppName)) + .textStyle(.body2Regular) + .foregroundColor(.app.gray2) + } + } + } + + private var title: String { + switch kind { + case .transaction: + L10n.TransactionReview.title + case .preAuthorization: + L10n.PreAuthorizationReview.title + } + } + } +} diff --git a/RadixWallet/Features/InteractionReview/Helpers/InteractionReview+Extra.swift b/RadixWallet/Features/InteractionReview/Helpers/InteractionReview+Extra.swift index 3e23aeab16..4114d04679 100644 --- a/RadixWallet/Features/InteractionReview/Helpers/InteractionReview+Extra.swift +++ b/RadixWallet/Features/InteractionReview/Helpers/InteractionReview+Extra.swift @@ -9,4 +9,6 @@ extension InteractionReview { ) static let transferLineTrailingPadding: CGFloat = .huge3 + + static let shadowColor: Color = .app.gray2.opacity(0.4) } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index 0c9a273099..1d1d9f3ef9 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -36,24 +36,10 @@ extension PreAuthorizationReview { struct View: SwiftUI.View { let store: StoreOf - @SwiftUI.State private var showNavigationTitle = false - - private let coordSpace: String = "PreAuthorizationReviewCoordSpace" - private let navTitleID: String = "PreAuthorizationReview.title" - private let showTitleHysteresis: CGFloat = .small3 - var body: some SwiftUI.View { WithViewStore(store, observe: \.viewState, send: { .view($0) }) { viewStore in content(viewStore) .controlState(viewStore.globalControlState) - .background(.app.white) - .toolbar { - ToolbarItem(placement: .principal) { - if showNavigationTitle { - navigationTitle(dAppName: viewStore.dAppName) - } - } - } .onAppear { store.send(.view(.appeared)) } @@ -61,25 +47,9 @@ extension PreAuthorizationReview { } } - private func navigationTitle(dAppName: String?) -> some SwiftUI.View { - VStack(spacing: .zero) { - Text(L10n.PreAuthorizationReview.title) - .textStyle(.body2Header) - .foregroundColor(.app.gray1) - - if let dAppName { - Text(L10n.PreAuthorizationReview.subtitle(dAppName)) - .textStyle(.body2Regular) - .foregroundColor(.app.gray2) - } - } - } - private func content(_ viewStore: ViewStoreOf) -> some SwiftUI.View { - ScrollView(showsIndicators: false) { - VStack(spacing: .zero) { - header(dAppMetadata: viewStore.dAppMetadata) - + Common.VisibleHeaderView(kind: .preAuthorization, metadata: viewStore.dAppMetadata) { + Group { Group { if let manifest = viewStore.displayMode.rawManifest { rawManifest(manifest) @@ -106,29 +76,6 @@ extension PreAuthorizationReview { } .animation(.easeInOut, value: viewStore.displayMode.rawManifest) } - .coordinateSpace(name: coordSpace) - .onPreferenceChange(PositionsPreferenceKey.self) { positions in - guard let offset = positions[navTitleID]?.maxY else { - showNavigationTitle = true - return - } - if showNavigationTitle, offset > showTitleHysteresis { - showNavigationTitle = false - } else if !showNavigationTitle, offset < 0 { - showNavigationTitle = true - } - } - } - - private func header(dAppMetadata: DappMetadata.Ledger?) -> some SwiftUI.View { - Common.HeaderView( - kind: .preAuthorization, - name: dAppMetadata?.name?.rawValue, - thumbnail: dAppMetadata?.thumbnail - ) - .measurePosition(navTitleID, coordSpace: coordSpace) - .padding(.horizontal, .medium3) - .padding(.bottom, .medium3) } private func rawManifest(_ manifest: String) -> some SwiftUI.View { diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index 40825abc85..ee1f4d56f7 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -59,16 +59,8 @@ extension TransactionReview { @MainActor struct View: SwiftUI.View { - @SwiftUI.State private var showNavigationTitle: Bool = false - private let store: StoreOf - private let coordSpace: String = "TransactionReviewCoordSpace" - private let navTitleID: String = "TransactionReview.title" - private let showTitleHysteresis: CGFloat = .small3 - - private let shadowColor: Color = .app.gray2.opacity(0.4) - init(store: StoreOf) { self.store = store } @@ -89,22 +81,6 @@ extension TransactionReview { .brightness(viewStore.rawManifest == nil ? 0 : -0.15) } } - - ToolbarItem(placement: .principal) { - if showNavigationTitle { - VStack(spacing: 0) { - Text(L10n.TransactionReview.title) - .textStyle(.body2Header) - .foregroundColor(.app.gray1) - - if let name = viewStore.proposingDappMetadata?.name { - Text(L10n.TransactionReview.proposingDappSubtitle(name.rawValue)) - .textStyle(.body2Regular) - .foregroundColor(.app.gray2) - } - } - } - } } .destinations(with: store) .onAppear { @@ -115,10 +91,8 @@ extension TransactionReview { @ViewBuilder private func coreView(with viewStore: ViewStoreOf) -> some SwiftUI.View { - ScrollView(showsIndicators: false) { - VStack(spacing: 0) { - header(viewStore.proposingDappMetadata) - + Common.VisibleHeaderView(kind: .transaction, metadata: viewStore.proposingDappMetadata) { + VStack(spacing: .zero) { if let manifest = viewStore.rawManifest { Common.RawManifestView(manifest: manifest) { viewStore.send(.copyRawTransactionTapped) @@ -154,38 +128,12 @@ extension TransactionReview { .padding(.vertical, .large3) .padding(.horizontal, .large2) .background { - JaggedEdge(shadowColor: shadowColor, isTopEdge: false) + JaggedEdge(shadowColor: Common.shadowColor, isTopEdge: false) } } .background(Common.gradientBackground) .animation(.easeInOut, value: viewStore.canToggleViewMode ? viewStore.rawManifest : nil) } - .coordinateSpace(name: coordSpace) - .onPreferenceChange(PositionsPreferenceKey.self) { positions in - guard let offset = positions[navTitleID]?.maxY else { - showNavigationTitle = true - return - } - if showNavigationTitle, offset > showTitleHysteresis { - showNavigationTitle = false - } else if !showNavigationTitle, offset < 0 { - showNavigationTitle = true - } - } - } - - private func header(_ proposingDappMetadata: DappMetadata.Ledger?) -> some SwiftUI.View { - Common.HeaderView( - kind: .transaction, - name: proposingDappMetadata?.name?.rawValue, - thumbnail: proposingDappMetadata?.thumbnail - ) - .measurePosition(navTitleID, coordSpace: coordSpace) - .padding(.horizontal, .medium3) - .padding(.bottom, .medium3) - .background { - JaggedEdge(shadowColor: shadowColor, isTopEdge: true) - } } @ViewBuilder From 7b4deac8fc2c55ad95c384b550dc4eda0d64cf5d Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Mon, 4 Nov 2024 21:12:05 +0100 Subject: [PATCH 58/63] Revert "VisibleHeaderView" This reverts commit 0be24a389c9582c057ae25b8a4b4ae1c3c3ea63b. --- RadixWallet.xcodeproj/project.pbxproj | 4 - .../Components/VisibleHeaderView.swift | 96 ------------------- .../Helpers/InteractionReview+Extra.swift | 2 - .../PreAuthorizationReview+View.swift | 57 ++++++++++- .../TransactionReview+View.swift | 58 ++++++++++- 5 files changed, 110 insertions(+), 107 deletions(-) delete mode 100644 RadixWallet/Features/InteractionReview/Components/VisibleHeaderView.swift diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index 89667af2de..159346b1ce 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -783,7 +783,6 @@ 5B8433A62CD011DE00CA00F5 /* PreAuthorizationClient+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8433A52CD011DC00CA00F5 /* PreAuthorizationClient+Test.swift */; }; 5B8433A82CD0128000CA00F5 /* PreAuthorizationClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8433A72CD0127900CA00F5 /* PreAuthorizationClient+Live.swift */; }; 5B8433AA2CD0131B00CA00F5 /* PreAuthorizationFailure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8433A92CD0131500CA00F5 /* PreAuthorizationFailure.swift */; }; - 5B8F770B2CD94CAD00154A76 /* VisibleHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F770A2CD94CA900154A76 /* VisibleHeaderView.swift */; }; 5B96DD372BD917B300722882 /* Text+Extra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B96DD362BD917B300722882 /* Text+Extra.swift */; }; 5B9846BD2BBD5C8800E814F3 /* SensitiveInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5B9846BC2BBD5C8800E814F3 /* SensitiveInfo.plist */; }; 5B9846C02BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9846BF2BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift */; }; @@ -2021,7 +2020,6 @@ 5B8433A52CD011DC00CA00F5 /* PreAuthorizationClient+Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationClient+Test.swift"; sourceTree = ""; }; 5B8433A72CD0127900CA00F5 /* PreAuthorizationClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationClient+Live.swift"; sourceTree = ""; }; 5B8433A92CD0131500CA00F5 /* PreAuthorizationFailure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreAuthorizationFailure.swift; sourceTree = ""; }; - 5B8F770A2CD94CA900154A76 /* VisibleHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisibleHeaderView.swift; sourceTree = ""; }; 5B96DD362BD917B300722882 /* Text+Extra.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Text+Extra.swift"; sourceTree = ""; }; 5B9846BC2BBD5C8800E814F3 /* SensitiveInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = SensitiveInfo.plist; sourceTree = ""; }; 5B9846BF2BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SensitiveInfoClient+Interface.swift"; sourceTree = ""; }; @@ -5541,7 +5539,6 @@ 5B27FBE82CC70AC2002975BE /* Components */ = { isa = PBXGroup; children = ( - 5B8F770A2CD94CA900154A76 /* VisibleHeaderView.swift */, 5B27FBD82CC67655002975BE /* HeadingView.swift */, 5B27FBEB2CC70E87002975BE /* ExpandableHeadingView.swift */, 5B03E3D42CC1487400E10A64 /* TransferLineView.swift */, @@ -7597,7 +7594,6 @@ 48CFC4042ADC10D900E77A5C /* KeychainHolder.swift in Sources */, 48CFC4392ADC10DA00E77A5C /* Sorted.swift in Sources */, 5B272DD92C36E93100B74F1F /* AppEventsClient+Live.swift in Sources */, - 5B8F770B2CD94CAD00154A76 /* VisibleHeaderView.swift in Sources */, 48CFC34B2ADC10D900E77A5C /* OneTimePersonaData.swift in Sources */, A408159A2C7E0D08005E65B9 /* MetadataOriginArrayValue.swift in Sources */, 48CFC3832ADC10D900E77A5C /* GeneralHelperViews.swift in Sources */, diff --git a/RadixWallet/Features/InteractionReview/Components/VisibleHeaderView.swift b/RadixWallet/Features/InteractionReview/Components/VisibleHeaderView.swift deleted file mode 100644 index 4fe61aa7f2..0000000000 --- a/RadixWallet/Features/InteractionReview/Components/VisibleHeaderView.swift +++ /dev/null @@ -1,96 +0,0 @@ -import SwiftUI - -extension InteractionReview { - struct VisibleHeaderView: SwiftUI.View { - let kind: InteractionReview.Kind - let metadata: DappMetadata.Ledger? - let content: Content - - init( - kind: InteractionReview.Kind, - metadata: DappMetadata.Ledger?, - @ViewBuilder content: () -> Content - ) { - self.kind = kind - self.metadata = metadata - self.content = content() - } - - @SwiftUI.State private var showNavigationTitle = false - - private let coordSpace: String = "InteractionReviewCoordSpace" - private let navTitleID: String = "InteractionReview.title" - private let showTitleHysteresis: CGFloat = .small3 - - var body: some View { - ScrollView(showsIndicators: false) { - VStack(spacing: .zero) { - header - - content - } - } - .coordinateSpace(name: coordSpace) - .onPreferenceChange(PositionsPreferenceKey.self) { positions in - guard let offset = positions[navTitleID]?.maxY else { - showNavigationTitle = true - return - } - if showNavigationTitle, offset > showTitleHysteresis { - showNavigationTitle = false - } else if !showNavigationTitle, offset < 0 { - showNavigationTitle = true - } - } - .toolbar { - ToolbarItem(placement: .principal) { - if showNavigationTitle { - navigationTitle - } - } - } - } - - private var header: some SwiftUI.View { - Common.HeaderView( - kind: kind, - name: metadata?.name?.rawValue, - thumbnail: metadata?.thumbnail - ) - .measurePosition(navTitleID, coordSpace: coordSpace) - .padding(.horizontal, .medium3) - .padding(.bottom, .medium3) - .background { - switch kind { - case .transaction: - JaggedEdge(shadowColor: InteractionReview.shadowColor, isTopEdge: true) - case .preAuthorization: - EmptyView() - } - } - } - - private var navigationTitle: some SwiftUI.View { - VStack(spacing: .zero) { - Text(title) - .textStyle(.body2Header) - .foregroundColor(.app.gray1) - - if let dAppName = metadata?.name?.rawValue { - Text(L10n.PreAuthorizationReview.subtitle(dAppName)) - .textStyle(.body2Regular) - .foregroundColor(.app.gray2) - } - } - } - - private var title: String { - switch kind { - case .transaction: - L10n.TransactionReview.title - case .preAuthorization: - L10n.PreAuthorizationReview.title - } - } - } -} diff --git a/RadixWallet/Features/InteractionReview/Helpers/InteractionReview+Extra.swift b/RadixWallet/Features/InteractionReview/Helpers/InteractionReview+Extra.swift index 4114d04679..3e23aeab16 100644 --- a/RadixWallet/Features/InteractionReview/Helpers/InteractionReview+Extra.swift +++ b/RadixWallet/Features/InteractionReview/Helpers/InteractionReview+Extra.swift @@ -9,6 +9,4 @@ extension InteractionReview { ) static let transferLineTrailingPadding: CGFloat = .huge3 - - static let shadowColor: Color = .app.gray2.opacity(0.4) } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index 1d1d9f3ef9..0c9a273099 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -36,10 +36,24 @@ extension PreAuthorizationReview { struct View: SwiftUI.View { let store: StoreOf + @SwiftUI.State private var showNavigationTitle = false + + private let coordSpace: String = "PreAuthorizationReviewCoordSpace" + private let navTitleID: String = "PreAuthorizationReview.title" + private let showTitleHysteresis: CGFloat = .small3 + var body: some SwiftUI.View { WithViewStore(store, observe: \.viewState, send: { .view($0) }) { viewStore in content(viewStore) .controlState(viewStore.globalControlState) + .background(.app.white) + .toolbar { + ToolbarItem(placement: .principal) { + if showNavigationTitle { + navigationTitle(dAppName: viewStore.dAppName) + } + } + } .onAppear { store.send(.view(.appeared)) } @@ -47,9 +61,25 @@ extension PreAuthorizationReview { } } + private func navigationTitle(dAppName: String?) -> some SwiftUI.View { + VStack(spacing: .zero) { + Text(L10n.PreAuthorizationReview.title) + .textStyle(.body2Header) + .foregroundColor(.app.gray1) + + if let dAppName { + Text(L10n.PreAuthorizationReview.subtitle(dAppName)) + .textStyle(.body2Regular) + .foregroundColor(.app.gray2) + } + } + } + private func content(_ viewStore: ViewStoreOf) -> some SwiftUI.View { - Common.VisibleHeaderView(kind: .preAuthorization, metadata: viewStore.dAppMetadata) { - Group { + ScrollView(showsIndicators: false) { + VStack(spacing: .zero) { + header(dAppMetadata: viewStore.dAppMetadata) + Group { if let manifest = viewStore.displayMode.rawManifest { rawManifest(manifest) @@ -76,6 +106,29 @@ extension PreAuthorizationReview { } .animation(.easeInOut, value: viewStore.displayMode.rawManifest) } + .coordinateSpace(name: coordSpace) + .onPreferenceChange(PositionsPreferenceKey.self) { positions in + guard let offset = positions[navTitleID]?.maxY else { + showNavigationTitle = true + return + } + if showNavigationTitle, offset > showTitleHysteresis { + showNavigationTitle = false + } else if !showNavigationTitle, offset < 0 { + showNavigationTitle = true + } + } + } + + private func header(dAppMetadata: DappMetadata.Ledger?) -> some SwiftUI.View { + Common.HeaderView( + kind: .preAuthorization, + name: dAppMetadata?.name?.rawValue, + thumbnail: dAppMetadata?.thumbnail + ) + .measurePosition(navTitleID, coordSpace: coordSpace) + .padding(.horizontal, .medium3) + .padding(.bottom, .medium3) } private func rawManifest(_ manifest: String) -> some SwiftUI.View { diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index ee1f4d56f7..40825abc85 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -59,8 +59,16 @@ extension TransactionReview { @MainActor struct View: SwiftUI.View { + @SwiftUI.State private var showNavigationTitle: Bool = false + private let store: StoreOf + private let coordSpace: String = "TransactionReviewCoordSpace" + private let navTitleID: String = "TransactionReview.title" + private let showTitleHysteresis: CGFloat = .small3 + + private let shadowColor: Color = .app.gray2.opacity(0.4) + init(store: StoreOf) { self.store = store } @@ -81,6 +89,22 @@ extension TransactionReview { .brightness(viewStore.rawManifest == nil ? 0 : -0.15) } } + + ToolbarItem(placement: .principal) { + if showNavigationTitle { + VStack(spacing: 0) { + Text(L10n.TransactionReview.title) + .textStyle(.body2Header) + .foregroundColor(.app.gray1) + + if let name = viewStore.proposingDappMetadata?.name { + Text(L10n.TransactionReview.proposingDappSubtitle(name.rawValue)) + .textStyle(.body2Regular) + .foregroundColor(.app.gray2) + } + } + } + } } .destinations(with: store) .onAppear { @@ -91,8 +115,10 @@ extension TransactionReview { @ViewBuilder private func coreView(with viewStore: ViewStoreOf) -> some SwiftUI.View { - Common.VisibleHeaderView(kind: .transaction, metadata: viewStore.proposingDappMetadata) { - VStack(spacing: .zero) { + ScrollView(showsIndicators: false) { + VStack(spacing: 0) { + header(viewStore.proposingDappMetadata) + if let manifest = viewStore.rawManifest { Common.RawManifestView(manifest: manifest) { viewStore.send(.copyRawTransactionTapped) @@ -128,12 +154,38 @@ extension TransactionReview { .padding(.vertical, .large3) .padding(.horizontal, .large2) .background { - JaggedEdge(shadowColor: Common.shadowColor, isTopEdge: false) + JaggedEdge(shadowColor: shadowColor, isTopEdge: false) } } .background(Common.gradientBackground) .animation(.easeInOut, value: viewStore.canToggleViewMode ? viewStore.rawManifest : nil) } + .coordinateSpace(name: coordSpace) + .onPreferenceChange(PositionsPreferenceKey.self) { positions in + guard let offset = positions[navTitleID]?.maxY else { + showNavigationTitle = true + return + } + if showNavigationTitle, offset > showTitleHysteresis { + showNavigationTitle = false + } else if !showNavigationTitle, offset < 0 { + showNavigationTitle = true + } + } + } + + private func header(_ proposingDappMetadata: DappMetadata.Ledger?) -> some SwiftUI.View { + Common.HeaderView( + kind: .transaction, + name: proposingDappMetadata?.name?.rawValue, + thumbnail: proposingDappMetadata?.thumbnail + ) + .measurePosition(navTitleID, coordSpace: coordSpace) + .padding(.horizontal, .medium3) + .padding(.bottom, .medium3) + .background { + JaggedEdge(shadowColor: shadowColor, isTopEdge: true) + } } @ViewBuilder From ee7d68c73848bc280aa00e0dec91c616c2041ed1 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 5 Nov 2024 12:50:34 +0100 Subject: [PATCH 59/63] updates --- .../Components/RawManifestView.swift | 9 +++++---- .../InteractionReview/Helpers/DisplayMode.swift | 2 +- .../PreAuthorizationReview+View.swift | 2 -- .../PreAuthorizationReview.swift | 12 +----------- .../TransactionReview+View.swift | 4 +--- .../TransactionReviewFeature/TransactionReview.swift | 12 +----------- 6 files changed, 9 insertions(+), 32 deletions(-) diff --git a/RadixWallet/Features/InteractionReview/Components/RawManifestView.swift b/RadixWallet/Features/InteractionReview/Components/RawManifestView.swift index b0652aad5a..4aaf86e896 100644 --- a/RadixWallet/Features/InteractionReview/Components/RawManifestView.swift +++ b/RadixWallet/Features/InteractionReview/Components/RawManifestView.swift @@ -2,17 +2,16 @@ import SwiftUI extension InteractionReview { struct RawManifestView: SwiftUI.View { + @Dependency(\.pasteboardClient) var pasteboardClient + let manifest: String - let copyAction: () -> Void let toggleAction: (() -> Void)? init( manifest: String, - copyAction: @escaping () -> Void, toggleAction: (() -> Void)? = nil ) { self.manifest = manifest - self.copyAction = copyAction self.toggleAction = toggleAction } @@ -33,7 +32,9 @@ extension InteractionReview { } private var copyButton: some View { - Button(action: copyAction) { + Button { + pasteboardClient.copyString(manifest) + } label: { HStack(spacing: .small3) { AssetIcon(.asset(AssetResource.copy)) Text(L10n.Common.copy) diff --git a/RadixWallet/Features/InteractionReview/Helpers/DisplayMode.swift b/RadixWallet/Features/InteractionReview/Helpers/DisplayMode.swift index 75d4ce8022..b330d7a10c 100644 --- a/RadixWallet/Features/InteractionReview/Helpers/DisplayMode.swift +++ b/RadixWallet/Features/InteractionReview/Helpers/DisplayMode.swift @@ -3,7 +3,7 @@ import Foundation extension InteractionReview { enum DisplayMode: Sendable, Hashable { case detailed - case raw(String) + case raw(manifest: String) var rawManifest: String? { guard case let .raw(manifest) = self else { return nil } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index 0c9a273099..ba814fe947 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -133,8 +133,6 @@ extension PreAuthorizationReview { private func rawManifest(_ manifest: String) -> some SwiftUI.View { Common.RawManifestView(manifest: manifest) { - store.send(.view(.copyRawManifestButtonTapped)) - } toggleAction: { store.send(.view(.toggleDisplayModeButtonTapped)) } } diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift index ae7d6d1477..f88ef1966e 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview.swift @@ -25,7 +25,6 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { enum ViewAction: Sendable, Equatable { case appeared case toggleDisplayModeButtonTapped - case copyRawManifestButtonTapped } @CasePathable @@ -63,7 +62,6 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { } @Dependency(\.continuousClock) var clock - @Dependency(\.pasteboardClient) var pasteboardClient @Dependency(\.preAuthorizationClient) var preAuthorizationClient @Dependency(\.errorQueue) var errorQueue @@ -100,14 +98,6 @@ struct PreAuthorizationReview: Sendable, FeatureReducer { state.displayMode = .detailed return .none } - - case .copyRawManifestButtonTapped: - guard let manifest = state.displayMode.rawManifest else { - assertionFailure("Copy raw manifest button should only be visible in raw mode") - return .none - } - pasteboardClient.copyString(manifest) - return .none } } @@ -183,7 +173,7 @@ private extension PreAuthorizationReview { return .none } - state.displayMode = .raw(preview.manifest.manifestString) + state.displayMode = .raw(manifest: preview.manifest.manifestString) return .none } } diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift index 40825abc85..dfeedc9c1d 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview+View.swift @@ -120,9 +120,7 @@ extension TransactionReview { header(viewStore.proposingDappMetadata) if let manifest = viewStore.rawManifest { - Common.RawManifestView(manifest: manifest) { - viewStore.send(.copyRawTransactionTapped) - } + Common.RawManifestView(manifest: manifest) } else { VStack(spacing: .medium1) { messageSection(with: viewStore.message) diff --git a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift index 4b9c25bea1..1779e3d9b3 100644 --- a/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift +++ b/RadixWallet/Features/TransactionReviewFeature/TransactionReview.swift @@ -88,7 +88,6 @@ struct TransactionReview: Sendable, FeatureReducer { enum ViewAction: Sendable, Equatable { case appeared case showRawTransactionTapped - case copyRawTransactionTapped case approvalSliderSlid } @@ -155,7 +154,6 @@ struct TransactionReview: Sendable, FeatureReducer { @Dependency(\.onLedgerEntitiesClient) var onLedgerEntitiesClient @Dependency(\.continuousClock) var clock @Dependency(\.errorQueue) var errorQueue - @Dependency(\.pasteboardClient) var pasteboardClient init() {} @@ -203,14 +201,6 @@ struct TransactionReview: Sendable, FeatureReducer { return .none } - case .copyRawTransactionTapped: - guard case let .raw(manifest) = state.displayMode else { - assertionFailure("Copy raw manifest button should only be visible in raw transaction mode") - return .none - } - pasteboardClient.copyString(manifest) - return .none - case .approvalSliderSlid: state.canApproveTX = false state.printFeePayerInfo() @@ -491,7 +481,7 @@ extension TransactionReview { func showRawTransaction(_ state: inout State) -> Effect { do { let manifest = try transactionManifestWithWalletInstructionsAdded(state) - state.displayMode = .raw(manifest.instructionsString) + state.displayMode = .raw(manifest: manifest.instructionsString) } catch { errorQueue.schedule(error) } From eb3b78a69ac122984678a652c233f6a65abf2e39 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 5 Nov 2024 12:53:57 +0100 Subject: [PATCH 60/63] rename DappInteractionModels --- .../Coordinator/DappInteractionFlow.swift | 4 ++-- .../Coordinator/DappInteractionModels.swift | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift index 0747a961a6..4d6b855641 100644 --- a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift +++ b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionFlow.swift @@ -1023,7 +1023,7 @@ extension DappInteractionFlow.Path.State { challenge: item.challenge )) - case let .remote(.send(item)): + case let .remote(.submitTransaction(item)): self.state = .reviewTransaction(.init( unvalidatedManifest: item.unvalidatedManifest, nonce: .secureRandom(), @@ -1037,7 +1037,7 @@ extension DappInteractionFlow.Path.State { p2pRoute: p2pRoute )) - case let .remote(.subintent(item)): + case let .remote(.signSubintent(item)): self.state = .preAuthorizationReview(.init( unvalidatedManifest: item.unvalidatedManifest, expiration: item.expiration, diff --git a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionModels.swift b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionModels.swift index 9292dce1e1..2c038ae60b 100644 --- a/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionModels.swift +++ b/RadixWallet/Features/DappInteractionFeature/Coordinator/DappInteractionModels.swift @@ -109,10 +109,10 @@ extension DappToWalletInteraction { case accountsProofOfOwnership(AccountsProofOfOwnership) // transactions - case send(DappToWalletInteractionSendTransactionItem) + case submitTransaction(DappToWalletInteractionSendTransactionItem) // preAuthorization - case subintent(DappToWalletInteractionSubintentRequestItem) + case signSubintent(DappToWalletInteractionSubintentRequestItem) var priority: some Comparable { switch self { @@ -132,10 +132,10 @@ extension DappToWalletInteraction { case .accountsProofOfOwnership: 6 // transactions - case .send: + case .submitTransaction: 0 // preAuthorization - case .subintent: + case .signSubintent: 0 } } @@ -165,12 +165,12 @@ extension DappToWalletInteraction { items.proofOfOwnership.splitted case let .transaction(items): [ - .send(items.send), + .submitTransaction(items.send), ] .compactMap { $0 } case let .preAuthorization(items): [ - .subintent(items.request), + .signSubintent(items.request), ] } } From 85b7b555a060aa11762dec227462a7c353d6c749 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 5 Nov 2024 13:33:32 +0100 Subject: [PATCH 61/63] add TimeFormatter tests --- RadixWallet.xcodeproj/project.pbxproj | 24 ++++++++++++++ .../PreAuthorizationReview+View.swift | 32 ++----------------- .../TImeFormatter/TimeFormatter.swift | 29 +++++++++++++++++ .../PreAuthorizationReviewTests.swift | 27 ++++++++++++++++ 4 files changed, 82 insertions(+), 30 deletions(-) create mode 100644 RadixWallet/Features/PreAuthorizationReview/TImeFormatter/TimeFormatter.swift create mode 100644 RadixWalletTests/Features/PreAuthorizationReviewTests/PreAuthorizationReviewTests.swift diff --git a/RadixWallet.xcodeproj/project.pbxproj b/RadixWallet.xcodeproj/project.pbxproj index 159346b1ce..f17b9305ea 100644 --- a/RadixWallet.xcodeproj/project.pbxproj +++ b/RadixWallet.xcodeproj/project.pbxproj @@ -783,6 +783,8 @@ 5B8433A62CD011DE00CA00F5 /* PreAuthorizationClient+Test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8433A52CD011DC00CA00F5 /* PreAuthorizationClient+Test.swift */; }; 5B8433A82CD0128000CA00F5 /* PreAuthorizationClient+Live.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8433A72CD0127900CA00F5 /* PreAuthorizationClient+Live.swift */; }; 5B8433AA2CD0131B00CA00F5 /* PreAuthorizationFailure.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8433A92CD0131500CA00F5 /* PreAuthorizationFailure.swift */; }; + 5B8F77102CDA41B100154A76 /* TimeFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F770F2CDA41B100154A76 /* TimeFormatter.swift */; }; + 5B8F77132CDA41F800154A76 /* PreAuthorizationReviewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8F77122CDA41F800154A76 /* PreAuthorizationReviewTests.swift */; }; 5B96DD372BD917B300722882 /* Text+Extra.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B96DD362BD917B300722882 /* Text+Extra.swift */; }; 5B9846BD2BBD5C8800E814F3 /* SensitiveInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5B9846BC2BBD5C8800E814F3 /* SensitiveInfo.plist */; }; 5B9846C02BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B9846BF2BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift */; }; @@ -2020,6 +2022,8 @@ 5B8433A52CD011DC00CA00F5 /* PreAuthorizationClient+Test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationClient+Test.swift"; sourceTree = ""; }; 5B8433A72CD0127900CA00F5 /* PreAuthorizationClient+Live.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreAuthorizationClient+Live.swift"; sourceTree = ""; }; 5B8433A92CD0131500CA00F5 /* PreAuthorizationFailure.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreAuthorizationFailure.swift; sourceTree = ""; }; + 5B8F770F2CDA41B100154A76 /* TimeFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeFormatter.swift; sourceTree = ""; }; + 5B8F77122CDA41F800154A76 /* PreAuthorizationReviewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreAuthorizationReviewTests.swift; sourceTree = ""; }; 5B96DD362BD917B300722882 /* Text+Extra.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Text+Extra.swift"; sourceTree = ""; }; 5B9846BC2BBD5C8800E814F3 /* SensitiveInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = SensitiveInfo.plist; sourceTree = ""; }; 5B9846BF2BBD5F0800E814F3 /* SensitiveInfoClient+Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SensitiveInfoClient+Interface.swift"; sourceTree = ""; }; @@ -5638,6 +5642,7 @@ children = ( 5B4A1ABD2CC00FB800679EE6 /* PreAuthorizationReview.swift */, 5B4A1ABE2CC00FB800679EE6 /* PreAuthorizationReview+View.swift */, + 5B8F770E2CDA413000154A76 /* TImeFormatter */, ); path = PreAuthorizationReview; sourceTree = ""; @@ -5745,6 +5750,22 @@ path = Models; sourceTree = ""; }; + 5B8F770E2CDA413000154A76 /* TImeFormatter */ = { + isa = PBXGroup; + children = ( + 5B8F770F2CDA41B100154A76 /* TimeFormatter.swift */, + ); + path = TImeFormatter; + sourceTree = ""; + }; + 5B8F77112CDA41DC00154A76 /* PreAuthorizationReviewTests */ = { + isa = PBXGroup; + children = ( + 5B8F77122CDA41F800154A76 /* PreAuthorizationReviewTests.swift */, + ); + path = PreAuthorizationReviewTests; + sourceTree = ""; + }; 5B9846BE2BBD5EF600E814F3 /* SensitiveInfoClient */ = { isa = PBXGroup; children = ( @@ -6550,6 +6571,7 @@ E6DBA2732ADEBFB200A38425 /* Features */ = { isa = PBXGroup; children = ( + 5B8F77112CDA41DC00154A76 /* PreAuthorizationReviewTests */, 83EE474E2AF027CE00155F03 /* AssetTransferTests */, 8328806A2AE6724B0014FBF3 /* AccountPreferencesTests */, E6DBA2782ADEBFB200A38425 /* SettingsFeatureTests */, @@ -7240,6 +7262,7 @@ E6DBA3432ADEBFB300A38425 /* UserDefaultsClientTests.swift in Sources */, E6DBA31A2ADEBFB300A38425 /* DataChannelClientTests.swift in Sources */, E6DBA32B2ADEBFB300A38425 /* JSON+Sendable.swift in Sources */, + 5B8F77132CDA41F800154A76 /* PreAuthorizationReviewTests.swift in Sources */, E6DBA3202ADEBFB300A38425 /* PeerConnectionMocks.swift in Sources */, 4827520F2BDA5FAF007854E0 /* AppFeatureTests.swift in Sources */, 48FF43152AE43C7C00C568B9 /* TimeLimit.swift in Sources */, @@ -7587,6 +7610,7 @@ 48CFC2C92ADC10D900E77A5C /* FungibleResourceAsset+View.swift in Sources */, 5B6E11482C45835900C20F2D /* AccountCard+DataSource.swift in Sources */, 48CFC40F2ADC10DA00E77A5C /* Logger.swift in Sources */, + 5B8F77102CDA41B100154A76 /* TimeFormatter.swift in Sources */, 48CFC36C2ADC10D900E77A5C /* FungibleTokenDetails+View.swift in Sources */, A40815612C7E0D08005E65B9 /* AccountLockerVaultCollectionItemFungible.swift in Sources */, E65D6CE72BC9815B001D8A39 /* Stage2MigrateToSargon+AppPreferences.swift in Sources */, diff --git a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift index ba814fe947..d48aac2e79 100644 --- a/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift +++ b/RadixWallet/Features/PreAuthorizationReview/PreAuthorizationReview+View.swift @@ -188,7 +188,7 @@ extension PreAuthorizationReview { case .atTime: if let seconds = secondsToExpiration { if seconds > 0 { - let value = formatTime(seconds: seconds) + let value = TimeFormatter.format(seconds: seconds) Text(markdown: L10n.PreAuthorizationReview.Expiration.atTime(value), emphasizedColor: .app.account4pink, emphasizedFont: .app.body2Link) } else { Text(L10n.PreAuthorizationReview.Expiration.expired) @@ -196,7 +196,7 @@ extension PreAuthorizationReview { } case let .afterDelay(value): - let value = formatTime(seconds: Int(value.expireAfterSeconds)) + let value = TimeFormatter.format(seconds: Int(value.expireAfterSeconds)) Text(markdown: L10n.PreAuthorizationReview.Expiration.afterDelay(value), emphasizedColor: .app.account4pink, emphasizedFont: .app.body2Link) case nil: @@ -211,34 +211,6 @@ extension PreAuthorizationReview { } } -private extension PreAuthorizationReview.View { - /// Given an amount of seconds, returns a formatted String using the corresponding unit (days/hours/minutes/seconds). - /// A few examples on how should it look for each of them: - /// - `8 days` / `1 day` - /// - `23:21 hours` / `1:24 hour` - /// - `56:02 minutes` / `1:23 minute` - /// - `34 seconds` / `1 second` - func formatTime(seconds: Int) -> String { - typealias S = L10n.PreAuthorizationReview.TimeFormat - let minutes = seconds / 60 - let hours = minutes / 60 - let days = hours / 24 - if days > 0 { - return days == 1 ? S.day : S.days(days) - } else if hours > 0 { - let remainingMinutes = minutes % 60 - let formatted = String(format: "%d:%02d", hours, remainingMinutes) - return hours == 1 ? S.hour(formatted) : S.hours(formatted) - } else if minutes > 0 { - let remainingSeconds = seconds % 60 - let formatted = String(format: "%d:%02d", minutes, remainingSeconds) - return minutes == 1 ? S.minute(formatted) : S.minutes(formatted) - } else { - return seconds == 1 ? S.second : S.seconds(seconds) - } - } -} - private extension PreAuthorizationReview.State { var globalControlState: ControlState { preview != nil ? .enabled : .loading(.global(text: L10n.PreAuthorizationReview.loading)) diff --git a/RadixWallet/Features/PreAuthorizationReview/TImeFormatter/TimeFormatter.swift b/RadixWallet/Features/PreAuthorizationReview/TImeFormatter/TimeFormatter.swift new file mode 100644 index 0000000000..e7a09a58f6 --- /dev/null +++ b/RadixWallet/Features/PreAuthorizationReview/TImeFormatter/TimeFormatter.swift @@ -0,0 +1,29 @@ +extension PreAuthorizationReview { + /// Given an amount of seconds, returns a formatted String using the corresponding unit (days/hours/minutes/seconds). + /// A few examples on how should it look for each of them: + /// - `8 days` / `1 day` + /// - `23:21 hours` / `1:24 hour` + /// - `56:02 minutes` / `1:23 minute` + /// - `34 seconds` / `1 second` + enum TimeFormatter { + static func format(seconds: Int) -> String { + typealias S = L10n.PreAuthorizationReview.TimeFormat + let minutes = seconds / 60 + let hours = minutes / 60 + let days = hours / 24 + if days > 0 { + return days == 1 ? S.day : S.days(days) + } else if hours > 0 { + let remainingMinutes = minutes % 60 + let formatted = String(format: "%d:%02d", hours, remainingMinutes) + return hours == 1 ? S.hour(formatted) : S.hours(formatted) + } else if minutes > 0 { + let remainingSeconds = seconds % 60 + let formatted = String(format: "%d:%02d", minutes, remainingSeconds) + return minutes == 1 ? S.minute(formatted) : S.minutes(formatted) + } else { + return seconds == 1 ? S.second : S.seconds(seconds) + } + } + } +} diff --git a/RadixWalletTests/Features/PreAuthorizationReviewTests/PreAuthorizationReviewTests.swift b/RadixWalletTests/Features/PreAuthorizationReviewTests/PreAuthorizationReviewTests.swift new file mode 100644 index 0000000000..daf4b491ff --- /dev/null +++ b/RadixWalletTests/Features/PreAuthorizationReviewTests/PreAuthorizationReviewTests.swift @@ -0,0 +1,27 @@ +@testable import Radix_Wallet_Dev +import Testing + +struct PreAuthorizationReviewTests { + @Test func testTimeFormatter() async throws { + func verify(_ seconds: Int, _ expected: String) { + let result = PreAuthorizationReview.TimeFormatter.format(seconds: seconds) + #expect(result == expected) + } + let minute = 60 + let hour = 60 * minute + let day = 24 * hour + let values: [Int: String] = [ + 1: "1 second", + 34: "34 seconds", + minute + 23: "1:23 minute", + 56 * minute + 2: "56:02 minutes", + hour + 24 * minute: "1:24 hour" + 23 * hour + 21 * minute: "23:21 hours", + day: "1 day", + 8 * day: "8 days", + ] + for item in values { + verify(item.key, item.value) + } + } +} From dd60106997369c86692d5311701a938390202495 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Tue, 5 Nov 2024 17:06:35 +0100 Subject: [PATCH 62/63] formatter --- .../PreAuthorizationReviewTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RadixWalletTests/Features/PreAuthorizationReviewTests/PreAuthorizationReviewTests.swift b/RadixWalletTests/Features/PreAuthorizationReviewTests/PreAuthorizationReviewTests.swift index daf4b491ff..c7e6c1384e 100644 --- a/RadixWalletTests/Features/PreAuthorizationReviewTests/PreAuthorizationReviewTests.swift +++ b/RadixWalletTests/Features/PreAuthorizationReviewTests/PreAuthorizationReviewTests.swift @@ -15,7 +15,7 @@ struct PreAuthorizationReviewTests { 34: "34 seconds", minute + 23: "1:23 minute", 56 * minute + 2: "56:02 minutes", - hour + 24 * minute: "1:24 hour" + hour + 24 * minute: "1:24 hour", 23 * hour + 21 * minute: "23:21 hours", day: "1 day", 8 * day: "8 days", From bfec7d192d8c6192cf43f21a35294d8bcfe9e585 Mon Sep 17 00:00:00 2001 From: Matias Bzurovski Date: Wed, 6 Nov 2024 09:50:35 +0100 Subject: [PATCH 63/63] updates to time formatter --- .../PreAuthorizationReview/TImeFormatter/TimeFormatter.swift | 5 ++--- .../PreAuthorizationReviewTests.swift | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/RadixWallet/Features/PreAuthorizationReview/TImeFormatter/TimeFormatter.swift b/RadixWallet/Features/PreAuthorizationReview/TImeFormatter/TimeFormatter.swift index e7a09a58f6..e27e7e1592 100644 --- a/RadixWallet/Features/PreAuthorizationReview/TImeFormatter/TimeFormatter.swift +++ b/RadixWallet/Features/PreAuthorizationReview/TImeFormatter/TimeFormatter.swift @@ -3,7 +3,7 @@ extension PreAuthorizationReview { /// A few examples on how should it look for each of them: /// - `8 days` / `1 day` /// - `23:21 hours` / `1:24 hour` - /// - `56:02 minutes` / `1:23 minute` + /// - `56 minutes` / `1 minute` /// - `34 seconds` / `1 second` enum TimeFormatter { static func format(seconds: Int) -> String { @@ -18,8 +18,7 @@ extension PreAuthorizationReview { let formatted = String(format: "%d:%02d", hours, remainingMinutes) return hours == 1 ? S.hour(formatted) : S.hours(formatted) } else if minutes > 0 { - let remainingSeconds = seconds % 60 - let formatted = String(format: "%d:%02d", minutes, remainingSeconds) + let formatted = "\(minutes)" return minutes == 1 ? S.minute(formatted) : S.minutes(formatted) } else { return seconds == 1 ? S.second : S.seconds(seconds) diff --git a/RadixWalletTests/Features/PreAuthorizationReviewTests/PreAuthorizationReviewTests.swift b/RadixWalletTests/Features/PreAuthorizationReviewTests/PreAuthorizationReviewTests.swift index c7e6c1384e..5fb8fee2ae 100644 --- a/RadixWalletTests/Features/PreAuthorizationReviewTests/PreAuthorizationReviewTests.swift +++ b/RadixWalletTests/Features/PreAuthorizationReviewTests/PreAuthorizationReviewTests.swift @@ -13,8 +13,8 @@ struct PreAuthorizationReviewTests { let values: [Int: String] = [ 1: "1 second", 34: "34 seconds", - minute + 23: "1:23 minute", - 56 * minute + 2: "56:02 minutes", + minute + 23: "1 minute", + 56 * minute + 2: "56 minutes", hour + 24 * minute: "1:24 hour", 23 * hour + 21 * minute: "23:21 hours", day: "1 day",