mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-01 16:06:59 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
7382d413a6
@ -6444,3 +6444,5 @@ Sorry for the inconvenience.";
|
||||
"Checkout.OptionalTipItemPlaceholder" = "Enter Custom";
|
||||
|
||||
"VoiceChat.ReminderNotify" = "We will notify you when it starts.";
|
||||
|
||||
"Checkout.SuccessfulTooltip" = "You paid %1$@ for %2$@.";
|
||||
|
@ -80,6 +80,7 @@ public final class BotCheckoutController: ViewController {
|
||||
private let context: AccountContext
|
||||
private let invoice: TelegramMediaInvoice
|
||||
private let messageId: MessageId
|
||||
private let completed: (String, MessageId?) -> Void
|
||||
|
||||
private var presentationData: PresentationData
|
||||
|
||||
@ -87,11 +88,12 @@ public final class BotCheckoutController: ViewController {
|
||||
|
||||
private let inputData: Promise<BotCheckoutController.InputData?>
|
||||
|
||||
public init(context: AccountContext, invoice: TelegramMediaInvoice, messageId: MessageId, inputData: Promise<BotCheckoutController.InputData?>) {
|
||||
public init(context: AccountContext, invoice: TelegramMediaInvoice, messageId: MessageId, inputData: Promise<BotCheckoutController.InputData?>, completed: @escaping (String, MessageId?) -> Void) {
|
||||
self.context = context
|
||||
self.invoice = invoice
|
||||
self.messageId = messageId
|
||||
self.inputData = inputData
|
||||
self.completed = completed
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
@ -121,7 +123,7 @@ public final class BotCheckoutController: ViewController {
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
}, dismissAnimated: { [weak self] in
|
||||
self?.dismiss()
|
||||
})
|
||||
}, completed: self.completed)
|
||||
|
||||
//displayNode.enableInteractiveDismiss = true
|
||||
|
||||
|
@ -506,6 +506,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
private let messageId: MessageId
|
||||
private let present: (ViewController, Any?) -> Void
|
||||
private let dismissAnimated: () -> Void
|
||||
private let completed: (String, MessageId?) -> Void
|
||||
|
||||
private var stateValue = BotCheckoutControllerState()
|
||||
private let state = ValuePromise(BotCheckoutControllerState(), ignoreRepeated: true)
|
||||
@ -536,12 +537,13 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
private var passwordTip: String?
|
||||
private var passwordTipDisposable: Disposable?
|
||||
|
||||
init(controller: BotCheckoutController?, navigationBar: NavigationBar, updateNavigationOffset: @escaping (CGFloat) -> Void, context: AccountContext, invoice: TelegramMediaInvoice, messageId: MessageId, inputData: Promise<BotCheckoutController.InputData?>, present: @escaping (ViewController, Any?) -> Void, dismissAnimated: @escaping () -> Void) {
|
||||
init(controller: BotCheckoutController?, navigationBar: NavigationBar, updateNavigationOffset: @escaping (CGFloat) -> Void, context: AccountContext, invoice: TelegramMediaInvoice, messageId: MessageId, inputData: Promise<BotCheckoutController.InputData?>, present: @escaping (ViewController, Any?) -> Void, dismissAnimated: @escaping () -> Void, completed: @escaping (String, MessageId?) -> Void) {
|
||||
self.controller = controller
|
||||
self.context = context
|
||||
self.messageId = messageId
|
||||
self.present = present
|
||||
self.dismissAnimated = dismissAnimated
|
||||
self.completed = completed
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
@ -1213,6 +1215,9 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
tipAmount = 0
|
||||
}
|
||||
|
||||
let totalAmount = currentTotalPrice(paymentForm: paymentForm, validatedFormInfo: self.currentValidatedFormInfo, currentShippingOptionId: self.currentShippingOptionId, currentTip: self.currentTipAmount)
|
||||
let currencyValue = formatCurrencyAmount(totalAmount, currency: paymentForm.invoice.currency)
|
||||
|
||||
self.payDisposable.set((sendBotPaymentForm(account: self.context.account, messageId: self.messageId, formId: paymentForm.id, validatedInfoId: self.currentValidatedFormInfo?.id, shippingOptionId: self.currentShippingOptionId, tipAmount: tipAmount, credentials: credentials) |> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
if let strongSelf = self {
|
||||
strongSelf.inProgressDimNode.isUserInteractionEnabled = false
|
||||
@ -1227,19 +1232,32 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
strongSelf.applePayController = nil
|
||||
applePayController.presentingViewController?.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
let proceedWithCompletion: (Bool, MessageId?) -> Void = { success, receiptMessageId in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
if success {
|
||||
strongSelf.dismissAnimated()
|
||||
strongSelf.completed(currencyValue, receiptMessageId)
|
||||
} else {
|
||||
strongSelf.dismissAnimated()
|
||||
}
|
||||
}
|
||||
|
||||
switch result {
|
||||
case .done:
|
||||
strongSelf.dismissAnimated()
|
||||
case let .done(receiptMessageId):
|
||||
proceedWithCompletion(true, receiptMessageId)
|
||||
case let .externalVerificationRequired(url):
|
||||
strongSelf.updateActionButton()
|
||||
var dismissImpl: (() -> Void)?
|
||||
let controller = BotCheckoutWebInteractionController(context: strongSelf.context, url: url, intent: .externalVerification({ _ in
|
||||
dismissImpl?()
|
||||
var dismissImpl: ((Bool) -> Void)?
|
||||
let controller = BotCheckoutWebInteractionController(context: strongSelf.context, url: url, intent: .externalVerification({ success in
|
||||
dismissImpl?(success)
|
||||
}))
|
||||
dismissImpl = { [weak controller] in
|
||||
dismissImpl = { [weak controller] success in
|
||||
controller?.dismiss()
|
||||
self?.dismissAnimated()
|
||||
proceedWithCompletion(success, nil)
|
||||
}
|
||||
strongSelf.present(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}
|
||||
|
@ -985,6 +985,11 @@ public final class Transaction {
|
||||
assert(!self.disposed)
|
||||
self.postbox?.scanMessages(peerId: peerId, namespace: namespace, tag: tag, f)
|
||||
}
|
||||
|
||||
public func scanTopMessages(peerId: PeerId, namespace: MessageId.Namespace, limit: Int, _ f: (Message) -> Bool) {
|
||||
assert(!self.disposed)
|
||||
self.postbox?.scanTopMessages(peerId: peerId, namespace: namespace, limit: limit, f)
|
||||
}
|
||||
|
||||
public func scanMessageAttributes(peerId: PeerId, namespace: MessageId.Namespace, limit: Int, _ f: (MessageId, [MessageAttribute]) -> Bool) {
|
||||
self.postbox?.scanMessageAttributes(peerId: peerId, namespace: namespace, limit: limit, f)
|
||||
@ -3411,6 +3416,26 @@ public final class Postbox {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func scanTopMessages(peerId: PeerId, namespace: MessageId.Namespace, limit: Int, _ f: (Message) -> Bool) {
|
||||
let lowerBound = MessageIndex.lowerBound(peerId: peerId, namespace: namespace)
|
||||
var index = MessageIndex.upperBound(peerId: peerId, namespace: namespace)
|
||||
var remainingLimit = limit
|
||||
while remainingLimit > 0 {
|
||||
let messages = self.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: nil, threadId: nil, from: index, includeFrom: false, to: lowerBound, limit: 10)
|
||||
remainingLimit -= 10
|
||||
for message in messages {
|
||||
if !f(self.renderIntermediateMessage(message)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if let last = messages.last {
|
||||
index = last.index
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func scanMessageAttributes(peerId: PeerId, namespace: MessageId.Namespace, limit: Int, _ f: (MessageId, [MessageAttribute]) -> Bool) {
|
||||
var remainingLimit = limit
|
||||
|
@ -342,7 +342,7 @@ public enum SendBotPaymentFormError {
|
||||
}
|
||||
|
||||
public enum SendBotPaymentResult {
|
||||
case done
|
||||
case done(receiptMessageId: MessageId?)
|
||||
case externalVerificationRequired(url: String)
|
||||
}
|
||||
|
||||
@ -384,7 +384,27 @@ public func sendBotPaymentForm(account: Account, messageId: MessageId, formId: I
|
||||
switch result {
|
||||
case let .paymentResult(updates):
|
||||
account.stateManager.addUpdates(updates)
|
||||
return .done
|
||||
var receiptMessageId: MessageId?
|
||||
for apiMessage in updates.messages {
|
||||
if let message = StoreMessage(apiMessage: apiMessage) {
|
||||
for media in message.media {
|
||||
if let action = media as? TelegramMediaAction {
|
||||
if case .paymentSent = action.action {
|
||||
for attribute in message.attributes {
|
||||
if let reply = attribute as? ReplyMessageAttribute {
|
||||
if reply.messageId == messageId {
|
||||
if case let .Id(id) = message.id {
|
||||
receiptMessageId = id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return .done(receiptMessageId: receiptMessageId)
|
||||
case let .paymentVerificationNeeded(url):
|
||||
return .externalVerificationRequired(url: url)
|
||||
}
|
||||
@ -402,13 +422,35 @@ public func sendBotPaymentForm(account: Account, messageId: MessageId, formId: I
|
||||
}
|
||||
}
|
||||
|
||||
public struct BotPaymentReceipt {
|
||||
public struct BotPaymentReceipt : Equatable {
|
||||
public let invoice: BotPaymentInvoice
|
||||
public let info: BotPaymentRequestedInfo?
|
||||
public let shippingOption: BotPaymentShippingOption?
|
||||
public let credentialsTitle: String
|
||||
public let invoiceMedia: TelegramMediaInvoice
|
||||
public let tipAmount: Int64?
|
||||
|
||||
public static func ==(lhs: BotPaymentReceipt, rhs: BotPaymentReceipt) -> Bool {
|
||||
if lhs.invoice != rhs.invoice {
|
||||
return false
|
||||
}
|
||||
if lhs.info != rhs.info {
|
||||
return false
|
||||
}
|
||||
if lhs.shippingOption != rhs.shippingOption {
|
||||
return false
|
||||
}
|
||||
if lhs.credentialsTitle != rhs.credentialsTitle {
|
||||
return false
|
||||
}
|
||||
if !lhs.invoiceMedia.isEqual(to: rhs.invoiceMedia) {
|
||||
return false
|
||||
}
|
||||
if lhs.tipAmount != rhs.tipAmount {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public enum RequestBotPaymentReceiptError {
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -1879,7 +1879,22 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|> `catch` { _ -> Signal<BotCheckoutController.InputData?, NoError> in
|
||||
return .single(nil)
|
||||
})
|
||||
strongSelf.present(BotCheckoutController(context: strongSelf.context, invoice: invoice, messageId: messageId, inputData: inputData), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
strongSelf.present(BotCheckoutController(context: strongSelf.context, invoice: invoice, messageId: messageId, inputData: inputData, completed: { currencyValue, receiptMessageId in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .paymentSent(currencyValue: currencyValue, itemTitle: invoice.title), elevatedLayout: false, action: { action in
|
||||
guard let strongSelf = self, let receiptMessageId = receiptMessageId else {
|
||||
return false
|
||||
}
|
||||
|
||||
if case .info = action {
|
||||
strongSelf.present(BotReceiptController(context: strongSelf.context, messageId: receiptMessageId), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}), in: .current)
|
||||
}), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ public enum UndoOverlayContent {
|
||||
case sticker(account: Account, file: TelegramMediaFile, text: String)
|
||||
case copy(text: String)
|
||||
case mediaSaved(text: String)
|
||||
case paymentSent(currencyValue: String, itemTitle: String)
|
||||
}
|
||||
|
||||
public enum UndoOverlayAction {
|
||||
|
@ -265,6 +265,23 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
string.addAttribute(.font, value: Font.regular(14.0), range: range)
|
||||
}
|
||||
|
||||
self.textNode.attributedText = string
|
||||
displayUndo = false
|
||||
self.originalRemainingSeconds = 5
|
||||
case let .paymentSent(currencyValue, itemTitle):
|
||||
self.avatarNode = nil
|
||||
self.iconNode = nil
|
||||
self.iconCheckNode = nil
|
||||
self.animationNode = AnimationNode(animation: "anim_payment", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
|
||||
self.animatedStickerNode = nil
|
||||
|
||||
let (rawString, attributes) = presentationData.strings.Checkout_SuccessfulTooltip(currencyValue, itemTitle)
|
||||
|
||||
let string = NSMutableAttributedString(attributedString: NSAttributedString(string: rawString, font: Font.regular(14.0), textColor: .white))
|
||||
for (_, range) in attributes {
|
||||
string.addAttribute(.font, value: Font.semibold(14.0), range: range)
|
||||
}
|
||||
|
||||
self.textNode.attributedText = string
|
||||
displayUndo = false
|
||||
self.originalRemainingSeconds = 5
|
||||
@ -738,7 +755,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
switch content {
|
||||
case .removedChat:
|
||||
self.panelWrapperNode.addSubnode(self.timerTextNode)
|
||||
case .archivedChat, .hidArchive, .revealedArchive, .autoDelete, .succeed, .emoji, .swipeToReply, .actionSucceeded, .stickersModified, .chatAddedToFolder, .chatRemovedFromFolder, .messagesUnpinned, .setProximityAlert, .invitedToVoiceChat, .linkCopied, .banned, .importedMessage, .audioRate, .forward, .gigagroupConversion, .linkRevoked, .voiceChatRecording, .voiceChatFlag, .voiceChatCanSpeak, .sticker, .copy, .mediaSaved:
|
||||
case .archivedChat, .hidArchive, .revealedArchive, .autoDelete, .succeed, .emoji, .swipeToReply, .actionSucceeded, .stickersModified, .chatAddedToFolder, .chatRemovedFromFolder, .messagesUnpinned, .setProximityAlert, .invitedToVoiceChat, .linkCopied, .banned, .importedMessage, .audioRate, .forward, .gigagroupConversion, .linkRevoked, .voiceChatRecording, .voiceChatFlag, .voiceChatCanSpeak, .sticker, .copy, .mediaSaved, .paymentSent:
|
||||
break
|
||||
case .dice:
|
||||
self.panelWrapperNode.clipsToBounds = true
|
||||
@ -864,6 +881,9 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
let factor: CGFloat = 0.07
|
||||
verticalOffset = -3.0
|
||||
preferredSize = CGSize(width: floor(iconSize.width * factor), height: floor(iconSize.height * factor))
|
||||
} else if case .paymentSent = self.content {
|
||||
let factor: CGFloat = 0.08
|
||||
preferredSize = CGSize(width: floor(iconSize.width * factor), height: floor(iconSize.height * factor))
|
||||
} else {
|
||||
preferredSize = iconSize
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user