mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-17 11:50:56 +00:00
Wallet: fix input focus change
Wallet: show alert when trying to send grams from transaction screen while wallet is busy updating
This commit is contained in:
parent
78d7745877
commit
c6dac0852c
@ -130,7 +130,7 @@ public final class WalletInfoScreen: ViewController {
|
|||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.push(WalletTransactionInfoScreen(context: strongSelf.context, walletInfo: strongSelf.walletInfo, walletTransaction: transaction, enableDebugActions: strongSelf.enableDebugActions))
|
strongSelf.push(WalletTransactionInfoScreen(context: strongSelf.context, walletInfo: strongSelf.walletInfo, walletTransaction: transaction, walletState: (strongSelf.displayNode as! WalletInfoScreenNode).statePromise.get(), enableDebugActions: strongSelf.enableDebugActions))
|
||||||
}, present: { [weak self] c, a in
|
}, present: { [weak self] c, a in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
@ -578,6 +578,8 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
|||||||
fileprivate var combinedState: CombinedWalletState?
|
fileprivate var combinedState: CombinedWalletState?
|
||||||
private var currentEntries: [WalletInfoListEntry]?
|
private var currentEntries: [WalletInfoListEntry]?
|
||||||
|
|
||||||
|
fileprivate let statePromise = Promise<(CombinedWalletState, Bool)>()
|
||||||
|
|
||||||
private var isReady: Bool = false
|
private var isReady: Bool = false
|
||||||
|
|
||||||
let contentReady = Promise<Bool>()
|
let contentReady = Promise<Bool>()
|
||||||
@ -817,6 +819,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
|||||||
self.transactionListDisposable.set(nil)
|
self.transactionListDisposable.set(nil)
|
||||||
self.loadingMoreTransactions = true
|
self.loadingMoreTransactions = true
|
||||||
self.reloadingState = true
|
self.reloadingState = true
|
||||||
|
self.updateStatePromise()
|
||||||
|
|
||||||
self.headerNode.isRefreshing = true
|
self.headerNode.isRefreshing = true
|
||||||
self.headerNode.refreshNode.refreshProgress = 0.0
|
self.headerNode.refreshNode.refreshProgress = 0.0
|
||||||
@ -853,6 +856,7 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
strongSelf.reloadingState = false
|
strongSelf.reloadingState = false
|
||||||
|
strongSelf.updateStatePromise()
|
||||||
|
|
||||||
if let combinedState = strongSelf.combinedState {
|
if let combinedState = strongSelf.combinedState {
|
||||||
strongSelf.headerNode.timestamp = Int32(clamping: combinedState.timestamp)
|
strongSelf.headerNode.timestamp = Int32(clamping: combinedState.timestamp)
|
||||||
@ -962,6 +966,14 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
|||||||
self.didSetContentReady = true
|
self.didSetContentReady = true
|
||||||
self.contentReady.set(.single(true))
|
self.contentReady.set(.single(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.updateStatePromise()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateStatePromise() {
|
||||||
|
if let combinedState = self.combinedState {
|
||||||
|
self.statePromise.set(.single((combinedState, self.reloadingState)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func loadMoreTransactions() {
|
private func loadMoreTransactions() {
|
||||||
|
|||||||
@ -16,17 +16,17 @@ private final class WalletSendScreenArguments {
|
|||||||
let context: WalletContext
|
let context: WalletContext
|
||||||
let updateState: ((WalletSendScreenState) -> WalletSendScreenState) -> Void
|
let updateState: ((WalletSendScreenState) -> WalletSendScreenState) -> Void
|
||||||
let updateText: (WalletSendScreenEntryTag, String) -> Void
|
let updateText: (WalletSendScreenEntryTag, String) -> Void
|
||||||
let selectNextInputItem: (WalletSendScreenEntryTag) -> Void
|
let selectInputItem: (WalletSendScreenEntryTag) -> Void
|
||||||
let scrollToBottom: () -> Void
|
let scrollToBottom: () -> Void
|
||||||
let dismissInput: () -> Void
|
let dismissInput: () -> Void
|
||||||
let openQrScanner: () -> Void
|
let openQrScanner: () -> Void
|
||||||
let proceed: () -> Void
|
let proceed: () -> Void
|
||||||
|
|
||||||
init(context: WalletContext, updateState: @escaping ((WalletSendScreenState) -> WalletSendScreenState) -> Void, updateText: @escaping (WalletSendScreenEntryTag, String) -> Void, selectNextInputItem: @escaping (WalletSendScreenEntryTag) -> Void, scrollToBottom: @escaping () -> Void, dismissInput: @escaping () -> Void, openQrScanner: @escaping () -> Void, proceed: @escaping () -> Void) {
|
init(context: WalletContext, updateState: @escaping ((WalletSendScreenState) -> WalletSendScreenState) -> Void, updateText: @escaping (WalletSendScreenEntryTag, String) -> Void, selectInputItem: @escaping (WalletSendScreenEntryTag) -> Void, scrollToBottom: @escaping () -> Void, dismissInput: @escaping () -> Void, openQrScanner: @escaping () -> Void, proceed: @escaping () -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.updateState = updateState
|
self.updateState = updateState
|
||||||
self.updateText = updateText
|
self.updateText = updateText
|
||||||
self.selectNextInputItem = selectNextInputItem
|
self.selectInputItem = selectInputItem
|
||||||
self.scrollToBottom = scrollToBottom
|
self.scrollToBottom = scrollToBottom
|
||||||
self.dismissInput = dismissInput
|
self.dismissInput = dismissInput
|
||||||
self.openQrScanner = openQrScanner
|
self.openQrScanner = openQrScanner
|
||||||
@ -190,28 +190,54 @@ private enum WalletSendScreenEntry: ItemListNodeEntry {
|
|||||||
if let amount = parsedUrl.amount {
|
if let amount = parsedUrl.amount {
|
||||||
state.amount = formatBalanceText(amount, decimalSeparator: arguments.context.presentationData.dateTimeFormat.decimalSeparator)
|
state.amount = formatBalanceText(amount, decimalSeparator: arguments.context.presentationData.dateTimeFormat.decimalSeparator)
|
||||||
} else if state.amount.isEmpty {
|
} else if state.amount.isEmpty {
|
||||||
focusItemTag = WalletSendScreenEntryTag.address
|
focusItemTag = WalletSendScreenEntryTag.amount
|
||||||
}
|
}
|
||||||
if let comment = parsedUrl.comment {
|
if let comment = parsedUrl.comment {
|
||||||
state.comment = comment
|
state.comment = comment
|
||||||
} else if state.comment.isEmpty && focusItemTag == nil {
|
} else if state.comment.isEmpty && focusItemTag == nil {
|
||||||
focusItemTag = WalletSendScreenEntryTag.amount
|
focusItemTag = WalletSendScreenEntryTag.comment
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
if let focusItemTag = focusItemTag {
|
if let focusItemTag = focusItemTag {
|
||||||
arguments.selectNextInputItem(focusItemTag)
|
arguments.selectInputItem(focusItemTag)
|
||||||
} else {
|
} else {
|
||||||
arguments.dismissInput()
|
arguments.dismissInput()
|
||||||
}
|
}
|
||||||
} else if isValidAddress(text) {
|
} else if isValidAddress(text) {
|
||||||
arguments.updateText(WalletSendScreenEntryTag.address, text)
|
arguments.updateText(WalletSendScreenEntryTag.address, text)
|
||||||
if isValidAddress(text, exactLength: true) {
|
if isValidAddress(text, exactLength: true) {
|
||||||
arguments.selectNextInputItem(WalletSendScreenEntryTag.address)
|
var focusItemTag: WalletSendScreenEntryTag? = .comment
|
||||||
|
arguments.updateState { state in
|
||||||
|
if state.amount.isEmpty {
|
||||||
|
focusItemTag = .amount
|
||||||
|
} else if state.comment.isEmpty {
|
||||||
|
focusItemTag = .comment
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
if let focusItemTag = focusItemTag {
|
||||||
|
arguments.selectInputItem(focusItemTag)
|
||||||
|
} else {
|
||||||
|
arguments.dismissInput()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, tag: WalletSendScreenEntryTag.address, action: {
|
}, tag: WalletSendScreenEntryTag.address, action: {
|
||||||
arguments.selectNextInputItem(WalletSendScreenEntryTag.address)
|
var focusItemTag: WalletSendScreenEntryTag?
|
||||||
|
arguments.updateState { state in
|
||||||
|
if state.amount.isEmpty {
|
||||||
|
focusItemTag = .amount
|
||||||
|
} else if state.comment.isEmpty {
|
||||||
|
focusItemTag = .comment
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
if let focusItemTag = focusItemTag {
|
||||||
|
arguments.selectInputItem(focusItemTag)
|
||||||
|
} else {
|
||||||
|
arguments.dismissInput()
|
||||||
|
}
|
||||||
}, inlineAction: ItemListMultilineInputInlineAction(icon: UIImage(bundleImageName: "Wallet/QrIcon")!, action: {
|
}, inlineAction: ItemListMultilineInputInlineAction(icon: UIImage(bundleImageName: "Wallet/QrIcon")!, action: {
|
||||||
arguments.openQrScanner()
|
arguments.openQrScanner()
|
||||||
}))
|
}))
|
||||||
@ -290,7 +316,7 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
|||||||
var popImpl: (() -> Void)?
|
var popImpl: (() -> Void)?
|
||||||
var dismissImpl: (() -> Void)?
|
var dismissImpl: (() -> Void)?
|
||||||
var dismissInputImpl: (() -> Void)?
|
var dismissInputImpl: (() -> Void)?
|
||||||
var selectNextInputItemImpl: ((WalletSendScreenEntryTag) -> Void)?
|
var selectInputItemImpl: ((WalletSendScreenEntryTag) -> Void)?
|
||||||
var ensureItemVisibleImpl: ((WalletSendScreenEntryTag, Bool) -> Void)?
|
var ensureItemVisibleImpl: ((WalletSendScreenEntryTag, Bool) -> Void)?
|
||||||
|
|
||||||
let arguments = WalletSendScreenArguments(context: context, updateState: { f in
|
let arguments = WalletSendScreenArguments(context: context, updateState: { f in
|
||||||
@ -309,8 +335,8 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
|||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
ensureItemVisibleImpl?(tag, false)
|
ensureItemVisibleImpl?(tag, false)
|
||||||
}, selectNextInputItem: { tag in
|
}, selectInputItem: { tag in
|
||||||
selectNextInputItemImpl?(tag)
|
selectInputItemImpl?(tag)
|
||||||
}, scrollToBottom: {
|
}, scrollToBottom: {
|
||||||
ensureItemVisibleImpl?(WalletSendScreenEntryTag.comment, true)
|
ensureItemVisibleImpl?(WalletSendScreenEntryTag.comment, true)
|
||||||
}, dismissInput: {
|
}, dismissInput: {
|
||||||
@ -336,9 +362,9 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
|||||||
popImpl?()
|
popImpl?()
|
||||||
if let updatedState = updatedState {
|
if let updatedState = updatedState {
|
||||||
if updatedState.amount.isEmpty {
|
if updatedState.amount.isEmpty {
|
||||||
selectNextInputItemImpl?(WalletSendScreenEntryTag.amount)
|
selectInputItemImpl?(WalletSendScreenEntryTag.amount)
|
||||||
} else if updatedState.comment.isEmpty {
|
} else if updatedState.comment.isEmpty {
|
||||||
selectNextInputItemImpl?(WalletSendScreenEntryTag.comment)
|
selectInputItemImpl?(WalletSendScreenEntryTag.comment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
@ -572,19 +598,16 @@ public func walletSendScreen(context: WalletContext, randomId: Int64, walletInfo
|
|||||||
dismissInputImpl = { [weak controller] in
|
dismissInputImpl = { [weak controller] in
|
||||||
controller?.view.endEditing(true)
|
controller?.view.endEditing(true)
|
||||||
}
|
}
|
||||||
selectNextInputItemImpl = { [weak controller] currentTag in
|
selectInputItemImpl = { [weak controller] nextTag in
|
||||||
guard let controller = controller else {
|
guard let controller = controller else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var resultItemNode: ItemListItemFocusableNode?
|
var resultItemNode: ItemListItemFocusableNode?
|
||||||
var focusOnNext = false
|
|
||||||
let _ = controller.frameForItemNode({ itemNode in
|
let _ = controller.frameForItemNode({ itemNode in
|
||||||
if let itemNode = itemNode as? ItemListItemNode, let tag = itemNode.tag, let focusableItemNode = itemNode as? ItemListItemFocusableNode {
|
if let itemNode = itemNode as? ItemListItemNode, let tag = itemNode.tag, let focusableItemNode = itemNode as? ItemListItemFocusableNode {
|
||||||
if focusOnNext && resultItemNode == nil {
|
if nextTag.isEqual(to: tag) {
|
||||||
resultItemNode = focusableItemNode
|
resultItemNode = focusableItemNode
|
||||||
return true
|
return true
|
||||||
} else if currentTag.isEqual(to: tag) {
|
|
||||||
focusOnNext = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@ -147,16 +147,22 @@ final class WalletTransactionInfoScreen: ViewController {
|
|||||||
private let context: WalletContext
|
private let context: WalletContext
|
||||||
private let walletInfo: WalletInfo?
|
private let walletInfo: WalletInfo?
|
||||||
private let walletTransaction: WalletInfoTransaction
|
private let walletTransaction: WalletInfoTransaction
|
||||||
|
private let walletState: Signal<(CombinedWalletState, Bool), NoError>
|
||||||
private var presentationData: WalletPresentationData
|
private var presentationData: WalletPresentationData
|
||||||
|
|
||||||
|
private var walletStateDisposable: Disposable?
|
||||||
|
private var combinedState: CombinedWalletState?
|
||||||
|
private var reloadingState = false
|
||||||
|
|
||||||
private var previousScreenBrightness: CGFloat?
|
private var previousScreenBrightness: CGFloat?
|
||||||
private var displayLinkAnimator: DisplayLinkAnimator?
|
private var displayLinkAnimator: DisplayLinkAnimator?
|
||||||
private let idleTimerExtensionDisposable: Disposable
|
private let idleTimerExtensionDisposable: Disposable
|
||||||
|
|
||||||
public init(context: WalletContext, walletInfo: WalletInfo?, walletTransaction: WalletInfoTransaction, enableDebugActions: Bool) {
|
public init(context: WalletContext, walletInfo: WalletInfo?, walletTransaction: WalletInfoTransaction, walletState: Signal<(CombinedWalletState, Bool), NoError>, enableDebugActions: Bool) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.walletInfo = walletInfo
|
self.walletInfo = walletInfo
|
||||||
self.walletTransaction = walletTransaction
|
self.walletTransaction = walletTransaction
|
||||||
|
self.walletState = walletState
|
||||||
|
|
||||||
self.presentationData = context.presentationData
|
self.presentationData = context.presentationData
|
||||||
|
|
||||||
@ -174,10 +180,21 @@ final class WalletTransactionInfoScreen: ViewController {
|
|||||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: UIView())
|
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: UIView())
|
||||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Wallet_Navigation_Back, style: .plain, target: nil, action: nil)
|
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Wallet_Navigation_Back, style: .plain, target: nil, action: nil)
|
||||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Wallet_Navigation_Done, style: .done, target: self, action: #selector(self.donePressed))
|
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Wallet_Navigation_Done, style: .done, target: self, action: #selector(self.donePressed))
|
||||||
|
|
||||||
|
self.walletStateDisposable = (walletState
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] combinedState, reloadingState in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.combinedState = combinedState
|
||||||
|
strongSelf.reloadingState = reloadingState
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
self.idleTimerExtensionDisposable.dispose()
|
self.idleTimerExtensionDisposable.dispose()
|
||||||
|
self.walletStateDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
required init(coder aDecoder: NSCoder) {
|
required init(coder aDecoder: NSCoder) {
|
||||||
@ -190,6 +207,18 @@ final class WalletTransactionInfoScreen: ViewController {
|
|||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strongSelf.reloadingState {
|
||||||
|
strongSelf.present(standardTextAlertController(theme: strongSelf.presentationData.theme.alert, title: nil, text: strongSelf.presentationData.strings.Wallet_Send_SyncInProgress, actions: [
|
||||||
|
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Wallet_Alert_OK, action: {
|
||||||
|
})
|
||||||
|
]), in: .window(.root))
|
||||||
|
} else if let combinedState = strongSelf.combinedState, !combinedState.pendingTransactions.isEmpty {
|
||||||
|
strongSelf.present(standardTextAlertController(theme: strongSelf.presentationData.theme.alert, title: nil, text: strongSelf.presentationData.strings.Wallet_Send_TransactionInProgress, actions: [
|
||||||
|
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Wallet_Alert_OK, action: {
|
||||||
|
})
|
||||||
|
]), in: .window(.root))
|
||||||
|
} else {
|
||||||
var randomId: Int64 = 0
|
var randomId: Int64 = 0
|
||||||
arc4random_buf(&randomId, 8)
|
arc4random_buf(&randomId, 8)
|
||||||
if let walletInfo = strongSelf.walletInfo {
|
if let walletInfo = strongSelf.walletInfo {
|
||||||
@ -197,6 +226,7 @@ final class WalletTransactionInfoScreen: ViewController {
|
|||||||
strongSelf.dismiss()
|
strongSelf.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
(self.displayNode as! WalletTransactionInfoScreenNode).displayFeesTooltip = { [weak self] node, rect in
|
(self.displayNode as! WalletTransactionInfoScreenNode).displayFeesTooltip = { [weak self] node, rect in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user