From e5ae714e55cd787981d03b9aa44cdab5be78fc22 Mon Sep 17 00:00:00 2001 From: Nuo Xu Date: Wed, 11 Dec 2024 16:09:20 -0500 Subject: [PATCH] add speed up in tx status screen --- .../Stores/TransactionStatusStore.swift | 5 +- .../TransactionConfirmationView.swift | 2 +- .../TransactionStatusView.swift | 110 +++++++++++++----- .../Sources/BraveWallet/WalletStrings.swift | 14 +++ 4 files changed, 103 insertions(+), 28 deletions(-) diff --git a/ios/brave-ios/Sources/BraveWallet/Crypto/Stores/TransactionStatusStore.swift b/ios/brave-ios/Sources/BraveWallet/Crypto/Stores/TransactionStatusStore.swift index 8021f79bd3a8..f7fea6a5e2ac 100644 --- a/ios/brave-ios/Sources/BraveWallet/Crypto/Stores/TransactionStatusStore.swift +++ b/ios/brave-ios/Sources/BraveWallet/Crypto/Stores/TransactionStatusStore.swift @@ -13,7 +13,6 @@ import Strings public class TransactionStatusStore: ObservableObject, WalletObserverStore { @Published var activeTxStatus: BraveWallet.TransactionStatus { didSet { - print("Debug - tx status changed to \(activeTxStatus)") originalTxStatus = activeTxStatus } } @@ -52,6 +51,10 @@ public class TransactionStatusStore: ObservableObject, WalletObserverStore { } } + var isSpeedUpAvailable: Bool { + return activeParsedTx.transaction.coin == .eth + } + init( activeTxStatus: BraveWallet.TransactionStatus, activeTxParsed: ParsedTransaction, diff --git a/ios/brave-ios/Sources/BraveWallet/Crypto/Transaction Confirmations/TransactionConfirmationView.swift b/ios/brave-ios/Sources/BraveWallet/Crypto/Transaction Confirmations/TransactionConfirmationView.swift index b59bc3656e6b..551a34002434 100644 --- a/ios/brave-ios/Sources/BraveWallet/Crypto/Transaction Confirmations/TransactionConfirmationView.swift +++ b/ios/brave-ios/Sources/BraveWallet/Crypto/Transaction Confirmations/TransactionConfirmationView.swift @@ -153,7 +153,7 @@ struct TransactionConfirmationView: View { onDismiss() onViewInActivity() }, - onCancelCreated: { txId in + onFollowUpTxCreated: { txId in Task { @MainActor in // fetch and update `confirmationStore.unapprovedTxs` with this new tx with `txId` if await confirmationStore.updateAllTx(with: txId) == false { diff --git a/ios/brave-ios/Sources/BraveWallet/Crypto/Transaction Confirmations/TransactionStatusView.swift b/ios/brave-ios/Sources/BraveWallet/Crypto/Transaction Confirmations/TransactionStatusView.swift index aafea84cee6f..f014e448bb81 100644 --- a/ios/brave-ios/Sources/BraveWallet/Crypto/Transaction Confirmations/TransactionStatusView.swift +++ b/ios/brave-ios/Sources/BraveWallet/Crypto/Transaction Confirmations/TransactionStatusView.swift @@ -15,15 +15,19 @@ struct TransactionStatusView: View { let onDismiss: () -> Void var onViewInActivity: () -> Void - var onCancelCreated: (_ txId: String) -> Void + var onFollowUpTxCreated: (_ txId: String) -> Void @Environment(\.openURL) private var openWalletURL + @Environment(\.pixelLength) private var pixelLength @State private var isSpinning: Bool = false @State private var isConfirmSpinning: Bool = false @State private var isConfirmSpinningFinished: Bool = false @State private var scrollViewContentSize: CGSize = .zero @State private var isShowingTxCancellationConfirmation: Bool = false + @State private var speedUpTimer: Timer? + @State private var isShowingSpeedUpBanner: Bool = false + @State private var followUpActionError: String? @ViewBuilder private var statusIcon: some View { switch txStatusStore.activeTxStatus { @@ -560,11 +564,47 @@ struct TransactionStatusView: View { || txStatusStore.activeTxStatus == .confirmed } + private var speedUpView: some View { + HStack(spacing: 4) { + Text(Strings.Wallet.speedUpBannerTitle) + .foregroundColor(Color(braveSystemName: .systemfeedbackInfoText)) + .font(.subheadline) + .multilineTextAlignment(.leading) + Spacer() + Button { + Task { @MainActor in + let (txId, error) = await txStatusStore.handleTransactionFollowUpAction(.speedUp) + if let error { + followUpActionError = error + } else if let txId { + onFollowUpTxCreated(txId) + } + } + } label: { + Text(Strings.Wallet.speedUpButtonTitle) + .foregroundColor(Color(braveSystemName: .textInteractive)) + .font(.caption.weight(.semibold)) + .padding(6) + } + .overlay { + RoundedRectangle(cornerRadius: 8) + .stroke(Color(braveSystemName: .dividerInteractive), lineWidth: pixelLength) + } + } + .padding(16) + .background( + Color(braveSystemName: .systemfeedbackInfoBackground) + .clipShape(RoundedRectangle(cornerRadius: 8)) + ) + } + var body: some View { NavigationStack { GeometryReader { geometry in ScrollView(.vertical) { VStack { + speedUpView + .hidden(isHidden: !isShowingSpeedUpBanner) Spacer() txStatusIconView .padding(.bottom, 30) @@ -601,25 +641,60 @@ struct TransactionStatusView: View { txStatusStore: txStatusStore, onCancelCreationSucceeded: { isShowingTxCancellationConfirmation = false - onCancelCreated($0) + onFollowUpTxCreated($0) }, - onCancelCreationFailed: { - isShowingTxCancellationConfirmation = false - } + cancelError: $followUpActionError ) .padding(16) } ) } + .onChange(of: txStatusStore.activeTxStatus) { _ in + if txStatusStore.activeTxStatus != .submitted { + isShowingSpeedUpBanner = false + speedUpTimer?.invalidate() + speedUpTimer = nil + } + } + .alert( + isPresented: Binding( + get: { followUpActionError != nil }, + set: { + if !$0 { + followUpActionError = nil + isShowingTxCancellationConfirmation = false + } + } + ) + ) { + Alert( + title: Text(Strings.genericErrorTitle), + message: Text(followUpActionError ?? ""), + dismissButton: .default(Text(Strings.OKString)) + ) + } + .onAppear { + if txStatusStore.activeTxStatus == .submitted && txStatusStore.isSpeedUpAvailable { + speedUpTimer = Timer.scheduledTimer( + withTimeInterval: 5, + repeats: false, + block: { _ in + isShowingSpeedUpBanner = true + } + ) + } + } + .onDisappear { + speedUpTimer?.invalidate() + speedUpTimer = nil + } } } struct TxCancellationConfirmationView: View { var txStatusStore: TransactionStatusStore var onCancelCreationSucceeded: (_ txId: String) -> Void - var onCancelCreationFailed: () -> Void - - @State private var cancelError: String? + @Binding var cancelError: String? var body: some View { VStack { @@ -647,23 +722,6 @@ struct TxCancellationConfirmationView: View { .buttonStyle(BraveFilledButtonStyle(size: .large)) } .multilineTextAlignment(.center) - .alert( - isPresented: Binding( - get: { cancelError != nil }, - set: { - if !$0 { - cancelError = nil - onCancelCreationFailed() - } - } - ) - ) { - Alert( - title: Text(Strings.genericErrorTitle), - message: Text(cancelError ?? ""), - dismissButton: .default(Text(Strings.OKString)) - ) - } } } @@ -675,7 +733,7 @@ struct TransactionStatusView_Previews: PreviewProvider { networkStore: .previewStore, onDismiss: {}, onViewInActivity: {}, - onCancelCreated: { _ in } + onFollowUpTxCreated: { _ in } ) } } diff --git a/ios/brave-ios/Sources/BraveWallet/WalletStrings.swift b/ios/brave-ios/Sources/BraveWallet/WalletStrings.swift index b1b752554d4c..c0f784c5a9f1 100644 --- a/ios/brave-ios/Sources/BraveWallet/WalletStrings.swift +++ b/ios/brave-ios/Sources/BraveWallet/WalletStrings.swift @@ -4561,6 +4561,20 @@ extension Strings { value: "A new transaction will be created to cancel your existing transaction", comment: "The description inside the view when asking user to confirm they want to cancel a transaction." ) + public static let speedUpBannerTitle = NSLocalizedString( + "wallet.speedUpBannerTitle", + tableName: "BraveWallet", + bundle: .module, + value: "Take longer than expected?", + comment: "The title of the banner which will be displayed at the top of the transaction status screen when transaction is in submitted status and user wants to speed it up." + ) + public static let speedUpButtonTitle = NSLocalizedString( + "wallet.speedUpButtonTitle", + tableName: "BraveWallet", + bundle: .module, + value: "Speed up", + comment: "The button title for the button inside speed up banner." + ) public static let ensOffchainGatewayTitle = NSLocalizedString( "wallet.ensOffchainGatewayTitle", tableName: "BraveWallet",