mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Support new API
This commit is contained in:
parent
3009fe790f
commit
de34ab5efa
@ -24,12 +24,14 @@ final class BotCheckoutControllerArguments {
|
||||
fileprivate let openInfo: (BotCheckoutInfoControllerFocus) -> Void
|
||||
fileprivate let openPaymentMethod: () -> Void
|
||||
fileprivate let openShippingMethod: () -> Void
|
||||
fileprivate let openTip: () -> Void
|
||||
|
||||
fileprivate init(account: Account, openInfo: @escaping (BotCheckoutInfoControllerFocus) -> Void, openPaymentMethod: @escaping () -> Void, openShippingMethod: @escaping () -> Void) {
|
||||
fileprivate init(account: Account, openInfo: @escaping (BotCheckoutInfoControllerFocus) -> Void, openPaymentMethod: @escaping () -> Void, openShippingMethod: @escaping () -> Void, openTip: @escaping () -> Void) {
|
||||
self.account = account
|
||||
self.openInfo = openInfo
|
||||
self.openPaymentMethod = openPaymentMethod
|
||||
self.openShippingMethod = openShippingMethod
|
||||
self.openTip = openTip
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,6 +44,7 @@ private enum BotCheckoutSection: Int32 {
|
||||
enum BotCheckoutEntry: ItemListNodeEntry {
|
||||
case header(PresentationTheme, TelegramMediaInvoice, String)
|
||||
case price(Int, PresentationTheme, String, String, Bool)
|
||||
case tip(PresentationTheme, String, String)
|
||||
case paymentMethod(PresentationTheme, String, String)
|
||||
case shippingInfo(PresentationTheme, String, String)
|
||||
case shippingMethod(PresentationTheme, String, String)
|
||||
@ -66,18 +69,20 @@ enum BotCheckoutEntry: ItemListNodeEntry {
|
||||
return 0
|
||||
case let .price(index, _, _, _, _):
|
||||
return 1 + Int32(index)
|
||||
case .paymentMethod:
|
||||
return 10000 + 0
|
||||
case .shippingInfo:
|
||||
case .tip:
|
||||
return 10000 + 1
|
||||
case .shippingMethod:
|
||||
case .paymentMethod:
|
||||
return 10000 + 2
|
||||
case .nameInfo:
|
||||
case .shippingInfo:
|
||||
return 10000 + 3
|
||||
case .emailInfo:
|
||||
case .shippingMethod:
|
||||
return 10000 + 4
|
||||
case .phoneInfo:
|
||||
case .nameInfo:
|
||||
return 10000 + 5
|
||||
case .emailInfo:
|
||||
return 10000 + 6
|
||||
case .phoneInfo:
|
||||
return 10000 + 7
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,6 +124,12 @@ enum BotCheckoutEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .tip(lhsTheme, lhsText, lhsValue):
|
||||
if case let .tip(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .paymentMethod(lhsTheme, lhsText, lhsValue):
|
||||
if case let .paymentMethod(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
return true
|
||||
@ -169,27 +180,31 @@ enum BotCheckoutEntry: ItemListNodeEntry {
|
||||
return BotCheckoutHeaderItem(account: arguments.account, theme: theme, invoice: invoice, botName: botName, sectionId: self.section)
|
||||
case let .price(_, theme, text, value, isFinal):
|
||||
return BotCheckoutPriceItem(theme: theme, title: text, label: value, isFinal: isFinal, sectionId: self.section)
|
||||
case let .paymentMethod(theme, text, value):
|
||||
case let .tip(_, text, value):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||
arguments.openTip()
|
||||
})
|
||||
case let .paymentMethod(_, text, value):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||
arguments.openPaymentMethod()
|
||||
})
|
||||
case let .shippingInfo(theme, text, value):
|
||||
case let .shippingInfo(_, text, value):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||
arguments.openInfo(.address(.street1))
|
||||
})
|
||||
case let .shippingMethod(theme, text, value):
|
||||
case let .shippingMethod(_, text, value):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||
arguments.openShippingMethod()
|
||||
})
|
||||
case let .nameInfo(theme, text, value):
|
||||
case let .nameInfo(_, text, value):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||
arguments.openInfo(.name)
|
||||
})
|
||||
case let .emailInfo(theme, text, value):
|
||||
case let .emailInfo(_, text, value):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||
arguments.openInfo(.email)
|
||||
})
|
||||
case let .phoneInfo(theme, text, value):
|
||||
case let .phoneInfo(_, text, value):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
||||
arguments.openInfo(.phone)
|
||||
})
|
||||
@ -206,12 +221,16 @@ private struct BotCheckoutControllerState: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private func currentTotalPrice(paymentForm: BotPaymentForm?, validatedFormInfo: BotPaymentValidatedFormInfo?, currentShippingOptionId: String?) -> Int64 {
|
||||
private func currentTotalPrice(paymentForm: BotPaymentForm?, validatedFormInfo: BotPaymentValidatedFormInfo?, currentShippingOptionId: String?, currentTip: Int64?) -> Int64 {
|
||||
guard let paymentForm = paymentForm else {
|
||||
return 0
|
||||
}
|
||||
|
||||
var totalPrice: Int64 = 0
|
||||
|
||||
if let currentTip = currentTip {
|
||||
totalPrice += currentTip
|
||||
}
|
||||
|
||||
var index = 0
|
||||
for price in paymentForm.invoice.prices {
|
||||
@ -235,7 +254,7 @@ private func currentTotalPrice(paymentForm: BotPaymentForm?, validatedFormInfo:
|
||||
return totalPrice
|
||||
}
|
||||
|
||||
private func botCheckoutControllerEntries(presentationData: PresentationData, state: BotCheckoutControllerState, invoice: TelegramMediaInvoice, paymentForm: BotPaymentForm?, formInfo: BotPaymentRequestedInfo?, validatedFormInfo: BotPaymentValidatedFormInfo?, currentShippingOptionId: String?, currentPaymentMethod: BotCheckoutPaymentMethod?, botPeer: Peer?) -> [BotCheckoutEntry] {
|
||||
private func botCheckoutControllerEntries(presentationData: PresentationData, state: BotCheckoutControllerState, invoice: TelegramMediaInvoice, paymentForm: BotPaymentForm?, formInfo: BotPaymentRequestedInfo?, validatedFormInfo: BotPaymentValidatedFormInfo?, currentShippingOptionId: String?, currentPaymentMethod: BotCheckoutPaymentMethod?, currentTip: Int64?, botPeer: Peer?) -> [BotCheckoutEntry] {
|
||||
var entries: [BotCheckoutEntry] = []
|
||||
|
||||
var botName = ""
|
||||
@ -246,6 +265,10 @@ private func botCheckoutControllerEntries(presentationData: PresentationData, st
|
||||
|
||||
if let paymentForm = paymentForm {
|
||||
var totalPrice: Int64 = 0
|
||||
|
||||
if let currentTip = currentTip {
|
||||
totalPrice += currentTip
|
||||
}
|
||||
|
||||
var index = 0
|
||||
for price in paymentForm.invoice.prices {
|
||||
@ -275,6 +298,17 @@ private func botCheckoutControllerEntries(presentationData: PresentationData, st
|
||||
}
|
||||
|
||||
entries.append(.price(index, presentationData.theme, presentationData.strings.Checkout_TotalAmount, formatCurrencyAmount(totalPrice, currency: paymentForm.invoice.currency), true))
|
||||
|
||||
if let tip = paymentForm.invoice.tip {
|
||||
let tipTitle: String
|
||||
//TODO:localize
|
||||
if tip.min == 0 {
|
||||
tipTitle = "Tip (Optional)"
|
||||
} else {
|
||||
tipTitle = "Tip"
|
||||
}
|
||||
entries.append(.tip(presentationData.theme, tipTitle, "\(formatCurrencyAmount(currentTip ?? 0, currency: paymentForm.invoice.currency))"))
|
||||
}
|
||||
|
||||
var paymentMethodTitle = ""
|
||||
if let currentPaymentMethod = currentPaymentMethod {
|
||||
@ -383,12 +417,13 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
|
||||
private var presentationData: PresentationData
|
||||
|
||||
private let paymentFormAndInfo = Promise<(BotPaymentForm, BotPaymentRequestedInfo, BotPaymentValidatedFormInfo?, String?, BotCheckoutPaymentMethod?)?>(nil)
|
||||
private let paymentFormAndInfo = Promise<(BotPaymentForm, BotPaymentRequestedInfo, BotPaymentValidatedFormInfo?, String?, BotCheckoutPaymentMethod?, Int64?)?>(nil)
|
||||
private var paymentFormValue: BotPaymentForm?
|
||||
private var currentFormInfo: BotPaymentRequestedInfo?
|
||||
private var currentValidatedFormInfo: BotPaymentValidatedFormInfo?
|
||||
private var currentShippingOptionId: String?
|
||||
private var currentPaymentMethod: BotCheckoutPaymentMethod?
|
||||
private var currentTipAmount: Int64?
|
||||
private var formRequestDisposable: Disposable?
|
||||
|
||||
private let actionButton: BotCheckoutActionButton
|
||||
@ -408,6 +443,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
var openInfoImpl: ((BotCheckoutInfoControllerFocus) -> Void)?
|
||||
var openTipImpl: (() -> Void)?
|
||||
var openPaymentMethodImpl: (() -> Void)?
|
||||
var openShippingMethodImpl: (() -> Void)?
|
||||
|
||||
@ -417,12 +453,14 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
openPaymentMethodImpl?()
|
||||
}, openShippingMethod: {
|
||||
openShippingMethodImpl?()
|
||||
}, openTip: {
|
||||
openTipImpl?()
|
||||
})
|
||||
|
||||
let signal: Signal<(ItemListPresentationData, (ItemListNodeState, Any)), NoError> = combineLatest(context.sharedContext.presentationData, self.state.get(), paymentFormAndInfo.get(), context.account.postbox.loadedPeerWithId(messageId.peerId))
|
||||
|> map { presentationData, state, paymentFormAndInfo, botPeer -> (ItemListPresentationData, (ItemListNodeState, Any)) in
|
||||
let nodeState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: botCheckoutControllerEntries(presentationData: presentationData, state: state, invoice: invoice, paymentForm: paymentFormAndInfo?.0, formInfo: paymentFormAndInfo?.1, validatedFormInfo: paymentFormAndInfo?.2, currentShippingOptionId: paymentFormAndInfo?.3, currentPaymentMethod: paymentFormAndInfo?.4, botPeer: botPeer), style: .plain, focusItemTag: nil, emptyStateItem: nil, animateChanges: false)
|
||||
|
||||
|> map { presentationData, state, paymentFormAndInfo, botPeer -> (ItemListPresentationData, (ItemListNodeState, Any)) in
|
||||
let nodeState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: botCheckoutControllerEntries(presentationData: presentationData, state: state, invoice: invoice, paymentForm: paymentFormAndInfo?.0, formInfo: paymentFormAndInfo?.1, validatedFormInfo: paymentFormAndInfo?.2, currentShippingOptionId: paymentFormAndInfo?.3, currentPaymentMethod: paymentFormAndInfo?.4, currentTip: paymentFormAndInfo?.5, botPeer: botPeer), style: .plain, focusItemTag: nil, emptyStateItem: nil, animateChanges: false)
|
||||
|
||||
return (ItemListPresentationData(presentationData), (nodeState, arguments))
|
||||
}
|
||||
|
||||
@ -450,7 +488,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
updatedCurrentShippingOptionId = currentShippingOptionId
|
||||
}
|
||||
}
|
||||
strongSelf.paymentFormAndInfo.set(.single((paymentFormValue, formInfo, validatedInfo, updatedCurrentShippingOptionId, strongSelf.currentPaymentMethod)))
|
||||
strongSelf.paymentFormAndInfo.set(.single((paymentFormValue, formInfo, validatedInfo, updatedCurrentShippingOptionId, strongSelf.currentPaymentMethod, strongSelf.currentTipAmount)))
|
||||
|
||||
strongSelf.updateActionButton()
|
||||
}
|
||||
@ -461,7 +499,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
let applyPaymentMethod: (BotCheckoutPaymentMethod) -> Void = { [weak self] method in
|
||||
if let strongSelf = self, let paymentFormValue = strongSelf.paymentFormValue, let currentFormInfo = strongSelf.currentFormInfo {
|
||||
strongSelf.currentPaymentMethod = method
|
||||
strongSelf.paymentFormAndInfo.set(.single((paymentFormValue, currentFormInfo, strongSelf.currentValidatedFormInfo, strongSelf.currentShippingOptionId, strongSelf.currentPaymentMethod)))
|
||||
strongSelf.paymentFormAndInfo.set(.single((paymentFormValue, currentFormInfo, strongSelf.currentValidatedFormInfo, strongSelf.currentShippingOptionId, strongSelf.currentPaymentMethod, strongSelf.currentTipAmount)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -608,6 +646,43 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
openTipImpl = { [weak self] in
|
||||
if let strongSelf = self, let paymentFormValue = strongSelf.paymentFormValue {
|
||||
//TODO:localize
|
||||
let initialValue: String
|
||||
if let tipAmount = strongSelf.currentTipAmount, let value = currencyToFractionalAmount(value: tipAmount, currency: paymentFormValue.invoice.currency) {
|
||||
initialValue = "\(value)"
|
||||
} else {
|
||||
initialValue = "0"
|
||||
}
|
||||
let controller = tipEditController(sharedContext: strongSelf.context.sharedContext, account: strongSelf.context.account, forceTheme: nil, title: "Tip", text: "Enter Tip Amount", placeholder: "", value: initialValue, apply: { value in
|
||||
guard let strongSelf = self, let paymentFormValue = strongSelf.paymentFormValue, var currentFormInfo = strongSelf.currentFormInfo, let value = value else {
|
||||
return
|
||||
}
|
||||
|
||||
let tipAmount = fractionalToCurrencyAmount(value: (Double(value) ?? 0.0), currency: paymentFormValue.invoice.currency) ?? 0
|
||||
|
||||
currentFormInfo.tipAmount = tipAmount
|
||||
|
||||
let _ = (validateBotPaymentForm(account: strongSelf.context.account, saveInfo: false, messageId: strongSelf.messageId, formInfo: currentFormInfo)
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.currentValidatedFormInfo = result
|
||||
|
||||
strongSelf.currentTipAmount = tipAmount
|
||||
|
||||
strongSelf.paymentFormAndInfo.set(.single((paymentFormValue, currentFormInfo, strongSelf.currentValidatedFormInfo, strongSelf.currentShippingOptionId, strongSelf.currentPaymentMethod, strongSelf.currentTipAmount)))
|
||||
|
||||
strongSelf.updateActionButton()
|
||||
})
|
||||
})
|
||||
strongSelf.present(controller, nil)
|
||||
}
|
||||
}
|
||||
|
||||
openPaymentMethodImpl = { [weak self] in
|
||||
if let strongSelf = self, let paymentForm = strongSelf.paymentFormValue {
|
||||
@ -629,7 +704,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
strongSelf.present(BotCheckoutPaymentShippingOptionSheetController(context: strongSelf.context, currency: paymentFormValue.invoice.currency, options: shippingOptions, currentId: strongSelf.currentShippingOptionId, applyValue: { id in
|
||||
if let strongSelf = self, let paymentFormValue = strongSelf.paymentFormValue, let currentFormInfo = strongSelf.currentFormInfo {
|
||||
strongSelf.currentShippingOptionId = id
|
||||
strongSelf.paymentFormAndInfo.set(.single((paymentFormValue, currentFormInfo, strongSelf.currentValidatedFormInfo, strongSelf.currentShippingOptionId, strongSelf.currentPaymentMethod)))
|
||||
strongSelf.paymentFormAndInfo.set(.single((paymentFormValue, currentFormInfo, strongSelf.currentValidatedFormInfo, strongSelf.currentShippingOptionId, strongSelf.currentPaymentMethod, strongSelf.currentTipAmount)))
|
||||
|
||||
strongSelf.updateActionButton()
|
||||
}
|
||||
@ -640,7 +715,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
let formAndMaybeValidatedInfo = fetchBotPaymentForm(postbox: context.account.postbox, network: context.account.network, messageId: messageId)
|
||||
|> mapToSignal { paymentForm -> Signal<(BotPaymentForm, BotPaymentValidatedFormInfo?), BotPaymentFormRequestError> in
|
||||
if let current = paymentForm.savedInfo {
|
||||
return validateBotPaymentForm(network: context.account.network, saveInfo: true, messageId: messageId, formInfo: current)
|
||||
return validateBotPaymentForm(account: context.account, saveInfo: true, messageId: messageId, formInfo: current)
|
||||
|> mapError { _ -> BotPaymentFormRequestError in
|
||||
return .generic
|
||||
}
|
||||
@ -661,7 +736,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
if let current = form.savedInfo {
|
||||
savedInfo = current
|
||||
} else {
|
||||
savedInfo = BotPaymentRequestedInfo(name: nil, phone: nil, email: nil, shippingAddress: nil)
|
||||
savedInfo = BotPaymentRequestedInfo(name: nil, phone: nil, email: nil, shippingAddress: nil, tipAmount: nil)
|
||||
}
|
||||
strongSelf.paymentFormValue = form
|
||||
strongSelf.currentFormInfo = savedInfo
|
||||
@ -670,7 +745,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
strongSelf.currentPaymentMethod = .savedCredentials(savedCredentials)
|
||||
}
|
||||
strongSelf.actionButton.isEnabled = true
|
||||
strongSelf.paymentFormAndInfo.set(.single((form, savedInfo, validatedInfo, nil, strongSelf.currentPaymentMethod)))
|
||||
strongSelf.paymentFormAndInfo.set(.single((form, savedInfo, validatedInfo, nil, strongSelf.currentPaymentMethod, strongSelf.currentTipAmount)))
|
||||
|
||||
strongSelf.updateActionButton()
|
||||
}
|
||||
@ -692,7 +767,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
}
|
||||
|
||||
private func updateActionButton() {
|
||||
let totalAmount = currentTotalPrice(paymentForm: self.paymentFormValue, validatedFormInfo: self.currentValidatedFormInfo, currentShippingOptionId: self.currentShippingOptionId)
|
||||
let totalAmount = currentTotalPrice(paymentForm: self.paymentFormValue, validatedFormInfo: self.currentValidatedFormInfo, currentShippingOptionId: self.currentShippingOptionId, currentTip: self.currentTipAmount)
|
||||
let payString: String
|
||||
if let paymentForm = self.paymentFormValue, totalAmount > 0 {
|
||||
payString = self.presentationData.strings.Checkout_PayPrice(formatCurrencyAmount(totalAmount, currency: paymentForm.invoice.currency)).0
|
||||
@ -835,11 +910,14 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
var items: [PKPaymentSummaryItem] = []
|
||||
|
||||
var totalAmount: Int64 = 0
|
||||
|
||||
for price in paymentForm.invoice.prices {
|
||||
totalAmount += price.amount
|
||||
|
||||
let amount = NSDecimalNumber(value: Double(price.amount) * 0.01)
|
||||
items.append(PKPaymentSummaryItem(label: price.label, amount: amount))
|
||||
|
||||
if let fractional = currencyToFractionalAmount(value: price.amount, currency: paymentForm.invoice.currency) {
|
||||
let amount = NSDecimalNumber(value: fractional)
|
||||
items.append(PKPaymentSummaryItem(label: price.label, amount: amount))
|
||||
}
|
||||
}
|
||||
|
||||
if let shippingOptions = strongSelf.currentValidatedFormInfo?.shippingOptions, let shippingOptionId = strongSelf.currentShippingOptionId {
|
||||
@ -852,9 +930,21 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let amount = NSDecimalNumber(value: Double(totalAmount) * 0.01)
|
||||
items.append(PKPaymentSummaryItem(label: botPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), amount: amount))
|
||||
|
||||
if let tipAmount = strongSelf.currentTipAmount {
|
||||
totalAmount += tipAmount
|
||||
|
||||
//TODO:localize
|
||||
if let fractional = currencyToFractionalAmount(value: tipAmount, currency: paymentForm.invoice.currency) {
|
||||
let amount = NSDecimalNumber(value: fractional)
|
||||
items.append(PKPaymentSummaryItem(label: "Tip", amount: amount))
|
||||
}
|
||||
}
|
||||
|
||||
if let fractionalTotal = currencyToFractionalAmount(value: totalAmount, currency: paymentForm.invoice.currency) {
|
||||
let amount = NSDecimalNumber(value: fractionalTotal)
|
||||
items.append(PKPaymentSummaryItem(label: botPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), amount: amount))
|
||||
}
|
||||
|
||||
request.paymentSummaryItems = items
|
||||
|
||||
@ -901,7 +991,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
self.inProgressDimNode.alpha = 1.0
|
||||
self.actionButton.isEnabled = false
|
||||
self.updateActionButton()
|
||||
self.payDisposable.set((sendBotPaymentForm(account: self.context.account, messageId: self.messageId, validatedInfoId: self.currentValidatedFormInfo?.id, shippingOptionId: self.currentShippingOptionId, credentials: credentials) |> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
self.payDisposable.set((sendBotPaymentForm(account: self.context.account, messageId: self.messageId, formId: paymentForm.id, validatedInfoId: self.currentValidatedFormInfo?.id, shippingOptionId: self.currentShippingOptionId, credentials: credentials) |> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
if let strongSelf = self {
|
||||
strongSelf.inProgressDimNode.isUserInteractionEnabled = false
|
||||
strongSelf.inProgressDimNode.alpha = 0.0
|
||||
|
@ -317,7 +317,7 @@ final class BotCheckoutInfoControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
shippingAddress = BotPaymentShippingAddress(streetLine1: "", streetLine2: "", city: "", state: "", countryIso2: iso2, postCode: "")
|
||||
}
|
||||
|
||||
self.formInfo = BotPaymentRequestedInfo(name: self.formInfo.name, phone: self.formInfo.phone, email: self.formInfo.email, shippingAddress: BotPaymentShippingAddress(streetLine1: shippingAddress.streetLine1, streetLine2: shippingAddress.streetLine2, city: shippingAddress.city, state: shippingAddress.state, countryIso2: iso2, postCode: shippingAddress.postCode))
|
||||
self.formInfo = BotPaymentRequestedInfo(name: self.formInfo.name, phone: self.formInfo.phone, email: self.formInfo.email, shippingAddress: BotPaymentShippingAddress(streetLine1: shippingAddress.streetLine1, streetLine2: shippingAddress.streetLine2, city: shippingAddress.city, state: shippingAddress.state, countryIso2: iso2, postCode: shippingAddress.postCode), tipAmount: self.formInfo.tipAmount)
|
||||
self.addressItems?.country.text = name
|
||||
if let containerLayout = self.containerLayout {
|
||||
self.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
|
||||
@ -332,13 +332,13 @@ final class BotCheckoutInfoControllerNode: ViewControllerTracingNode, UIScrollVi
|
||||
if let addressItems = self.addressItems, let current = self.formInfo.shippingAddress {
|
||||
address = BotPaymentShippingAddress(streetLine1: addressItems.address1.text, streetLine2: addressItems.address2.text, city: addressItems.city.text, state: addressItems.state.text, countryIso2: current.countryIso2, postCode: addressItems.postcode.text)
|
||||
}
|
||||
return BotPaymentRequestedInfo(name: self.nameItem?.text, phone: self.phoneItem?.text, email: self.emailItem?.text, shippingAddress: address)
|
||||
return BotPaymentRequestedInfo(name: self.nameItem?.text, phone: self.phoneItem?.text, email: self.emailItem?.text, shippingAddress: address, tipAmount: self.formInfo.tipAmount)
|
||||
}
|
||||
|
||||
func verify() {
|
||||
self.isVerifying = true
|
||||
let formInfo = self.collectFormInfo()
|
||||
self.verifyDisposable.set((validateBotPaymentForm(network: self.context.account.network, saveInfo: self.saveInfoItem.isOn, messageId: self.messageId, formInfo: formInfo) |> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
self.verifyDisposable.set((validateBotPaymentForm(account: self.context.account, saveInfo: self.saveInfoItem.isOn, messageId: self.messageId, formInfo: formInfo) |> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
if let strongSelf = self {
|
||||
strongSelf.formInfoUpdated(formInfo, result)
|
||||
}
|
||||
|
@ -287,7 +287,7 @@ final class BotReceiptControllerNode: ItemListControllerNode {
|
||||
|
||||
super.init(controller: controller, navigationBar: navigationBar, updateNavigationOffset: updateNavigationOffset, state: signal)
|
||||
|
||||
self.dataRequestDisposable = (requestBotPaymentReceipt(network: context.account.network, messageId: messageId) |> deliverOnMainQueue).start(next: { [weak self] receipt in
|
||||
self.dataRequestDisposable = (requestBotPaymentReceipt(account: context.account, messageId: messageId) |> deliverOnMainQueue).start(next: { [weak self] receipt in
|
||||
if let strongSelf = self {
|
||||
strongSelf.receiptData.set(.single((receipt.invoice, receipt.info, receipt.shippingOption, receipt.credentialsTitle)))
|
||||
}
|
||||
|
461
submodules/BotPaymentsUI/Sources/TipEditController.swift
Normal file
461
submodules/BotPaymentsUI/Sources/TipEditController.swift
Normal file
@ -0,0 +1,461 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SyncCore
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
|
||||
private final class TipEditInputFieldNode: ASDisplayNode, ASEditableTextNodeDelegate {
|
||||
private var theme: PresentationTheme
|
||||
private let backgroundNode: ASImageNode
|
||||
private let textInputNode: EditableTextNode
|
||||
private let placeholderNode: ASTextNode
|
||||
private let clearButton: HighlightableButtonNode
|
||||
|
||||
var updateHeight: (() -> Void)?
|
||||
var complete: (() -> Void)?
|
||||
var textChanged: ((String) -> Void)?
|
||||
|
||||
private let backgroundInsets = UIEdgeInsets(top: 8.0, left: 16.0, bottom: 15.0, right: 16.0)
|
||||
private let inputInsets = UIEdgeInsets(top: 5.0, left: 12.0, bottom: 5.0, right: 12.0)
|
||||
|
||||
var text: String {
|
||||
get {
|
||||
return self.textInputNode.attributedText?.string ?? ""
|
||||
}
|
||||
set {
|
||||
self.textInputNode.attributedText = NSAttributedString(string: newValue, font: Font.regular(17.0), textColor: self.theme.actionSheet.inputTextColor)
|
||||
self.placeholderNode.isHidden = !newValue.isEmpty
|
||||
self.clearButton.isHidden = newValue.isEmpty
|
||||
}
|
||||
}
|
||||
|
||||
var placeholder: String = "" {
|
||||
didSet {
|
||||
self.placeholderNode.attributedText = NSAttributedString(string: self.placeholder, font: Font.regular(17.0), textColor: self.theme.actionSheet.inputPlaceholderColor)
|
||||
}
|
||||
}
|
||||
|
||||
init(theme: PresentationTheme, placeholder: String) {
|
||||
self.theme = theme
|
||||
|
||||
self.backgroundNode = ASImageNode()
|
||||
self.backgroundNode.isLayerBacked = true
|
||||
self.backgroundNode.displaysAsynchronously = false
|
||||
self.backgroundNode.displayWithoutProcessing = true
|
||||
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 12.0, color: theme.actionSheet.inputHollowBackgroundColor, strokeColor: theme.actionSheet.inputBorderColor, strokeWidth: 1.0)
|
||||
|
||||
self.textInputNode = EditableTextNode()
|
||||
self.textInputNode.typingAttributes = [NSAttributedString.Key.font.rawValue: Font.regular(17.0), NSAttributedString.Key.foregroundColor.rawValue: theme.actionSheet.inputTextColor]
|
||||
self.textInputNode.clipsToBounds = true
|
||||
self.textInputNode.hitTestSlop = UIEdgeInsets(top: -5.0, left: -5.0, bottom: -5.0, right: -5.0)
|
||||
self.textInputNode.textContainerInset = UIEdgeInsets(top: self.inputInsets.top, left: 0.0, bottom: self.inputInsets.bottom, right: 0.0)
|
||||
self.textInputNode.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
|
||||
self.textInputNode.keyboardType = .default
|
||||
self.textInputNode.autocapitalizationType = .sentences
|
||||
self.textInputNode.returnKeyType = .done
|
||||
self.textInputNode.autocorrectionType = .default
|
||||
self.textInputNode.tintColor = theme.actionSheet.controlAccentColor
|
||||
|
||||
self.placeholderNode = ASTextNode()
|
||||
self.placeholderNode.isUserInteractionEnabled = false
|
||||
self.placeholderNode.displaysAsynchronously = false
|
||||
self.placeholderNode.attributedText = NSAttributedString(string: placeholder, font: Font.regular(17.0), textColor: self.theme.actionSheet.inputPlaceholderColor)
|
||||
|
||||
self.clearButton = HighlightableButtonNode()
|
||||
self.clearButton.imageNode.displaysAsynchronously = false
|
||||
self.clearButton.imageNode.displayWithoutProcessing = true
|
||||
self.clearButton.displaysAsynchronously = false
|
||||
self.clearButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Clear"), color: theme.actionSheet.inputClearButtonColor), for: [])
|
||||
self.clearButton.isHidden = true
|
||||
|
||||
super.init()
|
||||
|
||||
self.textInputNode.delegate = self
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.textInputNode)
|
||||
self.addSubnode(self.placeholderNode)
|
||||
self.addSubnode(self.clearButton)
|
||||
|
||||
self.clearButton.addTarget(self, action: #selector(self.clearPressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
|
||||
func updateTheme(_ theme: PresentationTheme) {
|
||||
self.theme = theme
|
||||
|
||||
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 12.0, color: self.theme.actionSheet.inputHollowBackgroundColor, strokeColor: self.theme.actionSheet.inputBorderColor, strokeWidth: 1.0)
|
||||
self.textInputNode.keyboardAppearance = self.theme.rootController.keyboardColor.keyboardAppearance
|
||||
self.placeholderNode.attributedText = NSAttributedString(string: self.placeholderNode.attributedText?.string ?? "", font: Font.regular(17.0), textColor: self.theme.actionSheet.inputPlaceholderColor)
|
||||
self.textInputNode.tintColor = self.theme.actionSheet.controlAccentColor
|
||||
self.clearButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Clear"), color: theme.actionSheet.inputClearButtonColor), for: [])
|
||||
}
|
||||
|
||||
func updateLayout(width: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||
let backgroundInsets = self.backgroundInsets
|
||||
let inputInsets = self.inputInsets
|
||||
|
||||
let textFieldHeight = self.calculateTextFieldMetrics(width: width)
|
||||
let panelHeight = textFieldHeight + backgroundInsets.top + backgroundInsets.bottom
|
||||
|
||||
let backgroundFrame = CGRect(origin: CGPoint(x: backgroundInsets.left, y: backgroundInsets.top), size: CGSize(width: width - backgroundInsets.left - backgroundInsets.right, height: panelHeight - backgroundInsets.top - backgroundInsets.bottom))
|
||||
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
|
||||
|
||||
let placeholderSize = self.placeholderNode.measure(backgroundFrame.size)
|
||||
transition.updateFrame(node: self.placeholderNode, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + inputInsets.left, y: backgroundFrame.minY + floor((backgroundFrame.size.height - placeholderSize.height) / 2.0)), size: placeholderSize))
|
||||
|
||||
transition.updateFrame(node: self.textInputNode, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + inputInsets.left, y: backgroundFrame.minY), size: CGSize(width: backgroundFrame.size.width - inputInsets.left - inputInsets.right - 20.0, height: backgroundFrame.size.height)))
|
||||
|
||||
if let image = self.clearButton.image(for: []) {
|
||||
transition.updateFrame(node: self.clearButton, frame: CGRect(origin: CGPoint(x: backgroundFrame.maxX - 8.0 - image.size.width, y: backgroundFrame.minY + floor((backgroundFrame.size.height - image.size.height) / 2.0)), size: image.size))
|
||||
}
|
||||
|
||||
return panelHeight
|
||||
}
|
||||
|
||||
func activateInput() {
|
||||
self.textInputNode.becomeFirstResponder()
|
||||
}
|
||||
|
||||
func deactivateInput() {
|
||||
self.textInputNode.resignFirstResponder()
|
||||
}
|
||||
|
||||
@objc func editableTextNodeDidUpdateText(_ editableTextNode: ASEditableTextNode) {
|
||||
self.updateTextNodeText(animated: true)
|
||||
self.textChanged?(editableTextNode.textView.text)
|
||||
self.placeholderNode.isHidden = !(editableTextNode.textView.text ?? "").isEmpty
|
||||
self.clearButton.isHidden = !self.placeholderNode.isHidden
|
||||
}
|
||||
|
||||
func editableTextNode(_ editableTextNode: ASEditableTextNode, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
|
||||
let updatedText = (editableTextNode.textView.text as NSString).replacingCharacters(in: range, with: text)
|
||||
if updatedText.count > 40 {
|
||||
self.textInputNode.layer.addShakeAnimation()
|
||||
return false
|
||||
}
|
||||
if text == "\n" {
|
||||
self.complete?()
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private func calculateTextFieldMetrics(width: CGFloat) -> CGFloat {
|
||||
let backgroundInsets = self.backgroundInsets
|
||||
let inputInsets = self.inputInsets
|
||||
|
||||
let unboundTextFieldHeight = max(33.0, ceil(self.textInputNode.measure(CGSize(width: width - backgroundInsets.left - backgroundInsets.right - inputInsets.left - inputInsets.right - 20.0, height: CGFloat.greatestFiniteMagnitude)).height))
|
||||
|
||||
return min(61.0, max(33.0, unboundTextFieldHeight))
|
||||
}
|
||||
|
||||
private func updateTextNodeText(animated: Bool) {
|
||||
let backgroundInsets = self.backgroundInsets
|
||||
|
||||
let textFieldHeight = self.calculateTextFieldMetrics(width: self.bounds.size.width)
|
||||
|
||||
let panelHeight = textFieldHeight + backgroundInsets.top + backgroundInsets.bottom
|
||||
if !self.bounds.size.height.isEqual(to: panelHeight) {
|
||||
self.updateHeight?()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func clearPressed() {
|
||||
self.placeholderNode.isHidden = false
|
||||
self.clearButton.isHidden = true
|
||||
|
||||
self.textInputNode.attributedText = nil
|
||||
self.deactivateInput()
|
||||
self.updateHeight?()
|
||||
}
|
||||
}
|
||||
|
||||
private final class TipEditAlertContentNode: AlertContentNode {
|
||||
private let strings: PresentationStrings
|
||||
private let title: String
|
||||
private let text: String
|
||||
|
||||
private let titleNode: ASTextNode
|
||||
private let textNode: ASTextNode
|
||||
let inputFieldNode: TipEditInputFieldNode
|
||||
|
||||
private let actionNodesSeparator: ASDisplayNode
|
||||
private let actionNodes: [TextAlertContentActionNode]
|
||||
private let actionVerticalSeparators: [ASDisplayNode]
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
|
||||
private var validLayout: CGSize?
|
||||
|
||||
private let hapticFeedback = HapticFeedback()
|
||||
|
||||
var complete: (() -> Void)? {
|
||||
didSet {
|
||||
self.inputFieldNode.complete = self.complete
|
||||
}
|
||||
}
|
||||
|
||||
override var dismissOnOutsideTap: Bool {
|
||||
return self.isUserInteractionEnabled
|
||||
}
|
||||
|
||||
init(theme: AlertControllerTheme, ptheme: PresentationTheme, strings: PresentationStrings, actions: [TextAlertAction], title: String, text: String, placeholder: String, value: String?) {
|
||||
self.strings = strings
|
||||
self.title = title
|
||||
self.text = text
|
||||
|
||||
self.titleNode = ASTextNode()
|
||||
self.titleNode.maximumNumberOfLines = 2
|
||||
self.textNode = ASTextNode()
|
||||
self.textNode.maximumNumberOfLines = 8
|
||||
|
||||
self.inputFieldNode = TipEditInputFieldNode(theme: ptheme, placeholder: placeholder)
|
||||
self.inputFieldNode.text = value ?? ""
|
||||
|
||||
self.actionNodesSeparator = ASDisplayNode()
|
||||
self.actionNodesSeparator.isLayerBacked = true
|
||||
|
||||
self.actionNodes = actions.map { action -> TextAlertContentActionNode in
|
||||
return TextAlertContentActionNode(theme: theme, action: action)
|
||||
}
|
||||
|
||||
var actionVerticalSeparators: [ASDisplayNode] = []
|
||||
if actions.count > 1 {
|
||||
for _ in 0 ..< actions.count - 1 {
|
||||
let separatorNode = ASDisplayNode()
|
||||
separatorNode.isLayerBacked = true
|
||||
actionVerticalSeparators.append(separatorNode)
|
||||
}
|
||||
}
|
||||
self.actionVerticalSeparators = actionVerticalSeparators
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.titleNode)
|
||||
self.addSubnode(self.textNode)
|
||||
|
||||
self.addSubnode(self.inputFieldNode)
|
||||
|
||||
self.addSubnode(self.actionNodesSeparator)
|
||||
|
||||
for actionNode in self.actionNodes {
|
||||
self.addSubnode(actionNode)
|
||||
}
|
||||
|
||||
for separatorNode in self.actionVerticalSeparators {
|
||||
self.addSubnode(separatorNode)
|
||||
}
|
||||
|
||||
self.inputFieldNode.updateHeight = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if let _ = strongSelf.validLayout {
|
||||
strongSelf.requestLayout?(.animated(duration: 0.15, curve: .spring))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.updateTheme(theme)
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
}
|
||||
|
||||
var value: String {
|
||||
return self.inputFieldNode.text
|
||||
}
|
||||
|
||||
override func updateTheme(_ theme: AlertControllerTheme) {
|
||||
self.titleNode.attributedText = NSAttributedString(string: self.title, font: Font.bold(17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
self.textNode.attributedText = NSAttributedString(string: self.text, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
|
||||
self.actionNodesSeparator.backgroundColor = theme.separatorColor
|
||||
for actionNode in self.actionNodes {
|
||||
actionNode.updateTheme(theme)
|
||||
}
|
||||
for separatorNode in self.actionVerticalSeparators {
|
||||
separatorNode.backgroundColor = theme.separatorColor
|
||||
}
|
||||
|
||||
if let size = self.validLayout {
|
||||
_ = self.updateLayout(size: size, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
override func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||
var size = size
|
||||
size.width = min(size.width, 270.0)
|
||||
let measureSize = CGSize(width: size.width - 16.0 * 2.0, height: CGFloat.greatestFiniteMagnitude)
|
||||
|
||||
let hadValidLayout = self.validLayout != nil
|
||||
|
||||
self.validLayout = size
|
||||
|
||||
var origin: CGPoint = CGPoint(x: 0.0, y: 20.0)
|
||||
let spacing: CGFloat = 5.0
|
||||
|
||||
let titleSize = self.titleNode.measure(measureSize)
|
||||
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - titleSize.width) / 2.0), y: origin.y), size: titleSize))
|
||||
origin.y += titleSize.height + 4.0
|
||||
|
||||
let textSize = self.textNode.measure(measureSize)
|
||||
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: origin.y), size: textSize))
|
||||
origin.y += textSize.height + 6.0 + spacing
|
||||
|
||||
let actionButtonHeight: CGFloat = 44.0
|
||||
var minActionsWidth: CGFloat = 0.0
|
||||
let maxActionWidth: CGFloat = floor(size.width / CGFloat(self.actionNodes.count))
|
||||
let actionTitleInsets: CGFloat = 8.0
|
||||
|
||||
var effectiveActionLayout = TextAlertContentActionLayout.horizontal
|
||||
for actionNode in self.actionNodes {
|
||||
let actionTitleSize = actionNode.titleNode.updateLayout(CGSize(width: maxActionWidth, height: actionButtonHeight))
|
||||
if case .horizontal = effectiveActionLayout, actionTitleSize.height > actionButtonHeight * 0.6667 {
|
||||
effectiveActionLayout = .vertical
|
||||
}
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
minActionsWidth += actionTitleSize.width + actionTitleInsets
|
||||
case .vertical:
|
||||
minActionsWidth = max(minActionsWidth, actionTitleSize.width + actionTitleInsets)
|
||||
}
|
||||
}
|
||||
|
||||
let insets = UIEdgeInsets(top: 18.0, left: 18.0, bottom: 9.0, right: 18.0)
|
||||
|
||||
var contentWidth = max(titleSize.width, minActionsWidth)
|
||||
contentWidth = max(contentWidth, 234.0)
|
||||
|
||||
var actionsHeight: CGFloat = 0.0
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
actionsHeight = actionButtonHeight
|
||||
case .vertical:
|
||||
actionsHeight = actionButtonHeight * CGFloat(self.actionNodes.count)
|
||||
}
|
||||
|
||||
let resultWidth = contentWidth + insets.left + insets.right
|
||||
|
||||
let inputFieldWidth = resultWidth
|
||||
let inputFieldHeight = self.inputFieldNode.updateLayout(width: inputFieldWidth, transition: transition)
|
||||
let inputHeight = inputFieldHeight
|
||||
transition.updateFrame(node: self.inputFieldNode, frame: CGRect(x: 0.0, y: origin.y, width: resultWidth, height: inputFieldHeight))
|
||||
transition.updateAlpha(node: self.inputFieldNode, alpha: inputHeight > 0.0 ? 1.0 : 0.0)
|
||||
|
||||
let resultSize = CGSize(width: resultWidth, height: titleSize.height + textSize.height + spacing + inputHeight + actionsHeight + insets.top + insets.bottom)
|
||||
|
||||
transition.updateFrame(node: self.actionNodesSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
|
||||
|
||||
var actionOffset: CGFloat = 0.0
|
||||
let actionWidth: CGFloat = floor(resultSize.width / CGFloat(self.actionNodes.count))
|
||||
var separatorIndex = -1
|
||||
var nodeIndex = 0
|
||||
for actionNode in self.actionNodes {
|
||||
if separatorIndex >= 0 {
|
||||
let separatorNode = self.actionVerticalSeparators[separatorIndex]
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: actionOffset - UIScreenPixel, y: resultSize.height - actionsHeight), size: CGSize(width: UIScreenPixel, height: actionsHeight - UIScreenPixel)))
|
||||
case .vertical:
|
||||
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
|
||||
}
|
||||
}
|
||||
separatorIndex += 1
|
||||
|
||||
let currentActionWidth: CGFloat
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
if nodeIndex == self.actionNodes.count - 1 {
|
||||
currentActionWidth = resultSize.width - actionOffset
|
||||
} else {
|
||||
currentActionWidth = actionWidth
|
||||
}
|
||||
case .vertical:
|
||||
currentActionWidth = resultSize.width
|
||||
}
|
||||
|
||||
let actionNodeFrame: CGRect
|
||||
switch effectiveActionLayout {
|
||||
case .horizontal:
|
||||
actionNodeFrame = CGRect(origin: CGPoint(x: actionOffset, y: resultSize.height - actionsHeight), size: CGSize(width: currentActionWidth, height: actionButtonHeight))
|
||||
actionOffset += currentActionWidth
|
||||
case .vertical:
|
||||
actionNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset), size: CGSize(width: currentActionWidth, height: actionButtonHeight))
|
||||
actionOffset += actionButtonHeight
|
||||
}
|
||||
|
||||
transition.updateFrame(node: actionNode, frame: actionNodeFrame)
|
||||
|
||||
nodeIndex += 1
|
||||
}
|
||||
|
||||
if !hadValidLayout {
|
||||
self.inputFieldNode.activateInput()
|
||||
}
|
||||
|
||||
return resultSize
|
||||
}
|
||||
|
||||
func animateError() {
|
||||
self.inputFieldNode.layer.addShakeAnimation()
|
||||
self.hapticFeedback.error()
|
||||
}
|
||||
}
|
||||
|
||||
func tipEditController(sharedContext: SharedAccountContext, account: Account, forceTheme: PresentationTheme?, title: String, text: String, placeholder: String, doneButtonTitle: String? = nil, value: String?, apply: @escaping (String?) -> Void) -> AlertController {
|
||||
var presentationData = sharedContext.currentPresentationData.with { $0 }
|
||||
if let forceTheme = forceTheme {
|
||||
presentationData = presentationData.withUpdated(theme: forceTheme)
|
||||
}
|
||||
|
||||
var dismissImpl: ((Bool) -> Void)?
|
||||
var applyImpl: (() -> Void)?
|
||||
|
||||
let actions: [TextAlertAction] = [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
|
||||
dismissImpl?(true)
|
||||
}), TextAlertAction(type: .defaultAction, title: doneButtonTitle ?? presentationData.strings.Common_Done, action: {
|
||||
applyImpl?()
|
||||
})]
|
||||
|
||||
let contentNode = TipEditAlertContentNode(theme: AlertControllerTheme(presentationData: presentationData), ptheme: presentationData.theme, strings: presentationData.strings, actions: actions, title: title, text: text, placeholder: placeholder, value: value)
|
||||
contentNode.complete = {
|
||||
applyImpl?()
|
||||
}
|
||||
applyImpl = { [weak contentNode] in
|
||||
guard let contentNode = contentNode else {
|
||||
return
|
||||
}
|
||||
dismissImpl?(true)
|
||||
|
||||
let previousValue = value ?? ""
|
||||
let newValue = contentNode.value.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
apply(previousValue != newValue || value == nil ? newValue : nil)
|
||||
}
|
||||
|
||||
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode)
|
||||
let presentationDataDisposable = sharedContext.presentationData.start(next: { [weak controller, weak contentNode] presentationData in
|
||||
var presentationData = presentationData
|
||||
if let forceTheme = forceTheme {
|
||||
presentationData = presentationData.withUpdated(theme: forceTheme)
|
||||
}
|
||||
controller?.theme = AlertControllerTheme(presentationData: presentationData)
|
||||
contentNode?.inputFieldNode.updateTheme(presentationData.theme)
|
||||
})
|
||||
controller.dismissed = {
|
||||
presentationDataDisposable.dispose()
|
||||
}
|
||||
dismissImpl = { [weak controller] animated in
|
||||
contentNode.inputFieldNode.deactivateInput()
|
||||
if animated {
|
||||
controller?.dismissAnimated()
|
||||
} else {
|
||||
controller?.dismiss()
|
||||
}
|
||||
}
|
||||
return controller
|
||||
}
|
@ -142,7 +142,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[767652808] = { return Api.InputEncryptedFile.parse_inputEncryptedFileBigUploaded($0) }
|
||||
dict[1304052993] = { return Api.account.Takeout.parse_takeout($0) }
|
||||
dict[-1456996667] = { return Api.messages.InactiveChats.parse_inactiveChats($0) }
|
||||
dict[-1184160274] = { return Api.GroupCallParticipant.parse_groupCallParticipant($0) }
|
||||
dict[430815881] = { return Api.GroupCallParticipant.parse_groupCallParticipant($0) }
|
||||
dict[1443858741] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedMessage($0) }
|
||||
dict[-1802240206] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedFile($0) }
|
||||
dict[289586518] = { return Api.SavedContact.parse_savedPhoneContact($0) }
|
||||
@ -156,7 +156,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1109531342] = { return Api.Peer.parse_peerChannel($0) }
|
||||
dict[410107472] = { return Api.messages.ExportedChatInvite.parse_exportedChatInvite($0) }
|
||||
dict[572915951] = { return Api.messages.ExportedChatInvite.parse_exportedChatInviteReplaced($0) }
|
||||
dict[-1868808300] = { return Api.PaymentRequestedInfo.parse_paymentRequestedInfo($0) }
|
||||
dict[-2017173756] = { return Api.PaymentRequestedInfo.parse_paymentRequestedInfo($0) }
|
||||
dict[164646985] = { return Api.UserStatus.parse_userStatusEmpty($0) }
|
||||
dict[-306628279] = { return Api.UserStatus.parse_userStatusOnline($0) }
|
||||
dict[9203775] = { return Api.UserStatus.parse_userStatusOffline($0) }
|
||||
@ -354,6 +354,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1098628881] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaVenue($0) }
|
||||
dict[-1494368259] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaContact($0) }
|
||||
dict[1262639204] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageGame($0) }
|
||||
dict[-717976187] = { return Api.InputBotInlineMessage.parse_inputBotInlineMessageMediaInvoice($0) }
|
||||
dict[2002815875] = { return Api.KeyboardButtonRow.parse_keyboardButtonRow($0) }
|
||||
dict[1088567208] = { return Api.StickerSet.parse_stickerSet($0) }
|
||||
dict[-1111085620] = { return Api.messages.ExportedChatInvites.parse_exportedChatInvites($0) }
|
||||
@ -587,7 +588,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[978610270] = { return Api.messages.Messages.parse_messagesSlice($0) }
|
||||
dict[1682413576] = { return Api.messages.Messages.parse_channelMessages($0) }
|
||||
dict[1951620897] = { return Api.messages.Messages.parse_messagesNotModified($0) }
|
||||
dict[-1022713000] = { return Api.Invoice.parse_invoice($0) }
|
||||
dict[615970509] = { return Api.Invoice.parse_invoice($0) }
|
||||
dict[1933519201] = { return Api.PeerSettings.parse_peerSettings($0) }
|
||||
dict[1577067778] = { return Api.auth.SentCode.parse_sentCode($0) }
|
||||
dict[480546647] = { return Api.InputChatPhoto.parse_inputChatPhotoEmpty($0) }
|
||||
@ -637,7 +638,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[935395612] = { return Api.ChatPhoto.parse_chatPhotoEmpty($0) }
|
||||
dict[-770990276] = { return Api.ChatPhoto.parse_chatPhoto($0) }
|
||||
dict[1869903447] = { return Api.PageCaption.parse_pageCaption($0) }
|
||||
dict[1062645411] = { return Api.payments.PaymentForm.parse_paymentForm($0) }
|
||||
dict[-1928649707] = { return Api.payments.PaymentForm.parse_paymentForm($0) }
|
||||
dict[1342771681] = { return Api.payments.PaymentReceipt.parse_paymentReceipt($0) }
|
||||
dict[863093588] = { return Api.messages.PeerDialogs.parse_peerDialogs($0) }
|
||||
dict[-1831650802] = { return Api.UrlAuthResult.parse_urlAuthResultRequest($0) }
|
||||
@ -754,6 +755,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[85477117] = { return Api.BotInlineMessage.parse_botInlineMessageMediaGeo($0) }
|
||||
dict[-1970903652] = { return Api.BotInlineMessage.parse_botInlineMessageMediaVenue($0) }
|
||||
dict[416402882] = { return Api.BotInlineMessage.parse_botInlineMessageMediaContact($0) }
|
||||
dict[894081801] = { return Api.BotInlineMessage.parse_botInlineMessageMediaInvoice($0) }
|
||||
dict[-1673717362] = { return Api.InputPeerNotifySettings.parse_inputPeerNotifySettings($0) }
|
||||
dict[-1634752813] = { return Api.messages.FavedStickers.parse_favedStickersNotModified($0) }
|
||||
dict[-209768682] = { return Api.messages.FavedStickers.parse_favedStickers($0) }
|
||||
|
@ -3604,13 +3604,13 @@ public extension Api {
|
||||
|
||||
}
|
||||
public enum GroupCallParticipant: TypeConstructorDescription {
|
||||
case groupCallParticipant(flags: Int32, peer: Api.Peer, date: Int32, activeDate: Int32?, source: Int32, volume: Int32?, about: String?, raiseHandRating: Int64?, params: Api.DataJSON?)
|
||||
case groupCallParticipant(flags: Int32, peer: Api.Peer, date: Int32, activeDate: Int32?, source: Int32, volume: Int32?, about: String?, raiseHandRating: Int64?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .groupCallParticipant(let flags, let peer, let date, let activeDate, let source, let volume, let about, let raiseHandRating, let params):
|
||||
case .groupCallParticipant(let flags, let peer, let date, let activeDate, let source, let volume, let about, let raiseHandRating):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1184160274)
|
||||
buffer.appendInt32(430815881)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
peer.serialize(buffer, true)
|
||||
@ -3620,15 +3620,14 @@ public extension Api {
|
||||
if Int(flags) & Int(1 << 7) != 0 {serializeInt32(volume!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 11) != 0 {serializeString(about!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 13) != 0 {serializeInt64(raiseHandRating!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 6) != 0 {params!.serialize(buffer, true)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .groupCallParticipant(let flags, let peer, let date, let activeDate, let source, let volume, let about, let raiseHandRating, let params):
|
||||
return ("groupCallParticipant", [("flags", flags), ("peer", peer), ("date", date), ("activeDate", activeDate), ("source", source), ("volume", volume), ("about", about), ("raiseHandRating", raiseHandRating), ("params", params)])
|
||||
case .groupCallParticipant(let flags, let peer, let date, let activeDate, let source, let volume, let about, let raiseHandRating):
|
||||
return ("groupCallParticipant", [("flags", flags), ("peer", peer), ("date", date), ("activeDate", activeDate), ("source", source), ("volume", volume), ("about", about), ("raiseHandRating", raiseHandRating)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -3651,10 +3650,6 @@ public extension Api {
|
||||
if Int(_1!) & Int(1 << 11) != 0 {_7 = parseString(reader) }
|
||||
var _8: Int64?
|
||||
if Int(_1!) & Int(1 << 13) != 0 {_8 = reader.readInt64() }
|
||||
var _9: Api.DataJSON?
|
||||
if Int(_1!) & Int(1 << 6) != 0 {if let signature = reader.readInt32() {
|
||||
_9 = Api.parse(reader, signature: signature) as? Api.DataJSON
|
||||
} }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
@ -3663,9 +3658,8 @@ public extension Api {
|
||||
let _c6 = (Int(_1!) & Int(1 << 7) == 0) || _6 != nil
|
||||
let _c7 = (Int(_1!) & Int(1 << 11) == 0) || _7 != nil
|
||||
let _c8 = (Int(_1!) & Int(1 << 13) == 0) || _8 != nil
|
||||
let _c9 = (Int(_1!) & Int(1 << 6) == 0) || _9 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 {
|
||||
return Api.GroupCallParticipant.groupCallParticipant(flags: _1!, peer: _2!, date: _3!, activeDate: _4, source: _5!, volume: _6, about: _7, raiseHandRating: _8, params: _9)
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
|
||||
return Api.GroupCallParticipant.groupCallParticipant(flags: _1!, peer: _2!, date: _3!, activeDate: _4, source: _5!, volume: _6, about: _7, raiseHandRating: _8)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
@ -3906,27 +3900,28 @@ public extension Api {
|
||||
|
||||
}
|
||||
public enum PaymentRequestedInfo: TypeConstructorDescription {
|
||||
case paymentRequestedInfo(flags: Int32, name: String?, phone: String?, email: String?, shippingAddress: Api.PostAddress?)
|
||||
case paymentRequestedInfo(flags: Int32, name: String?, phone: String?, email: String?, shippingAddress: Api.PostAddress?, tipAmount: Int64?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .paymentRequestedInfo(let flags, let name, let phone, let email, let shippingAddress):
|
||||
case .paymentRequestedInfo(let flags, let name, let phone, let email, let shippingAddress, let tipAmount):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1868808300)
|
||||
buffer.appendInt32(-2017173756)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeString(name!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 1) != 0 {serializeString(phone!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 2) != 0 {serializeString(email!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 3) != 0 {shippingAddress!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 4) != 0 {serializeInt64(tipAmount!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .paymentRequestedInfo(let flags, let name, let phone, let email, let shippingAddress):
|
||||
return ("paymentRequestedInfo", [("flags", flags), ("name", name), ("phone", phone), ("email", email), ("shippingAddress", shippingAddress)])
|
||||
case .paymentRequestedInfo(let flags, let name, let phone, let email, let shippingAddress, let tipAmount):
|
||||
return ("paymentRequestedInfo", [("flags", flags), ("name", name), ("phone", phone), ("email", email), ("shippingAddress", shippingAddress), ("tipAmount", tipAmount)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -3943,13 +3938,16 @@ public extension Api {
|
||||
if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
|
||||
_5 = Api.parse(reader, signature: signature) as? Api.PostAddress
|
||||
} }
|
||||
var _6: Int64?
|
||||
if Int(_1!) & Int(1 << 4) != 0 {_6 = reader.readInt64() }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil
|
||||
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
|
||||
let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||
return Api.PaymentRequestedInfo.paymentRequestedInfo(flags: _1!, name: _2, phone: _3, email: _4, shippingAddress: _5)
|
||||
let _c6 = (Int(_1!) & Int(1 << 4) == 0) || _6 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
||||
return Api.PaymentRequestedInfo.paymentRequestedInfo(flags: _1!, name: _2, phone: _3, email: _4, shippingAddress: _5, tipAmount: _6)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
@ -9078,6 +9076,7 @@ public extension Api {
|
||||
case inputBotInlineMessageMediaVenue(flags: Int32, geoPoint: Api.InputGeoPoint, title: String, address: String, provider: String, venueId: String, venueType: String, replyMarkup: Api.ReplyMarkup?)
|
||||
case inputBotInlineMessageMediaContact(flags: Int32, phoneNumber: String, firstName: String, lastName: String, vcard: String, replyMarkup: Api.ReplyMarkup?)
|
||||
case inputBotInlineMessageGame(flags: Int32, replyMarkup: Api.ReplyMarkup?)
|
||||
case inputBotInlineMessageMediaInvoice(flags: Int32, title: String, description: String, photo: Api.InputWebDocument?, invoice: Api.Invoice, payload: Buffer, provider: String, providerData: Api.DataJSON, startParam: String, replyMarkup: Api.ReplyMarkup?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
@ -9149,6 +9148,21 @@ public extension Api {
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)}
|
||||
break
|
||||
case .inputBotInlineMessageMediaInvoice(let flags, let title, let description, let photo, let invoice, let payload, let provider, let providerData, let startParam, let replyMarkup):
|
||||
if boxed {
|
||||
buffer.appendInt32(-717976187)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeString(title, buffer: buffer, boxed: false)
|
||||
serializeString(description, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {photo!.serialize(buffer, true)}
|
||||
invoice.serialize(buffer, true)
|
||||
serializeBytes(payload, buffer: buffer, boxed: false)
|
||||
serializeString(provider, buffer: buffer, boxed: false)
|
||||
providerData.serialize(buffer, true)
|
||||
serializeString(startParam, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -9166,6 +9180,8 @@ public extension Api {
|
||||
return ("inputBotInlineMessageMediaContact", [("flags", flags), ("phoneNumber", phoneNumber), ("firstName", firstName), ("lastName", lastName), ("vcard", vcard), ("replyMarkup", replyMarkup)])
|
||||
case .inputBotInlineMessageGame(let flags, let replyMarkup):
|
||||
return ("inputBotInlineMessageGame", [("flags", flags), ("replyMarkup", replyMarkup)])
|
||||
case .inputBotInlineMessageMediaInvoice(let flags, let title, let description, let photo, let invoice, let payload, let provider, let providerData, let startParam, let replyMarkup):
|
||||
return ("inputBotInlineMessageMediaInvoice", [("flags", flags), ("title", title), ("description", description), ("photo", photo), ("invoice", invoice), ("payload", payload), ("provider", provider), ("providerData", providerData), ("startParam", startParam), ("replyMarkup", replyMarkup)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -9327,6 +9343,52 @@ public extension Api {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_inputBotInlineMessageMediaInvoice(_ reader: BufferReader) -> InputBotInlineMessage? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: String?
|
||||
_2 = parseString(reader)
|
||||
var _3: String?
|
||||
_3 = parseString(reader)
|
||||
var _4: Api.InputWebDocument?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
|
||||
_4 = Api.parse(reader, signature: signature) as? Api.InputWebDocument
|
||||
} }
|
||||
var _5: Api.Invoice?
|
||||
if let signature = reader.readInt32() {
|
||||
_5 = Api.parse(reader, signature: signature) as? Api.Invoice
|
||||
}
|
||||
var _6: Buffer?
|
||||
_6 = parseBytes(reader)
|
||||
var _7: String?
|
||||
_7 = parseString(reader)
|
||||
var _8: Api.DataJSON?
|
||||
if let signature = reader.readInt32() {
|
||||
_8 = Api.parse(reader, signature: signature) as? Api.DataJSON
|
||||
}
|
||||
var _9: String?
|
||||
_9 = parseString(reader)
|
||||
var _10: Api.ReplyMarkup?
|
||||
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
|
||||
_10 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup
|
||||
} }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = _6 != nil
|
||||
let _c7 = _7 != nil
|
||||
let _c8 = _8 != nil
|
||||
let _c9 = _9 != nil
|
||||
let _c10 = (Int(_1!) & Int(1 << 2) == 0) || _10 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 {
|
||||
return Api.InputBotInlineMessage.inputBotInlineMessageMediaInvoice(flags: _1!, title: _2!, description: _3!, photo: _4, invoice: _5!, payload: _6!, provider: _7!, providerData: _8!, startParam: _9!, replyMarkup: _10)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public enum KeyboardButtonRow: TypeConstructorDescription {
|
||||
@ -15020,13 +15082,13 @@ public extension Api {
|
||||
|
||||
}
|
||||
public enum Invoice: TypeConstructorDescription {
|
||||
case invoice(flags: Int32, currency: String, prices: [Api.LabeledPrice])
|
||||
case invoice(flags: Int32, currency: String, prices: [Api.LabeledPrice], minTipAmount: Int64?, maxTipAmount: Int64?, defaultTipAmount: Int64?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .invoice(let flags, let currency, let prices):
|
||||
case .invoice(let flags, let currency, let prices, let minTipAmount, let maxTipAmount, let defaultTipAmount):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1022713000)
|
||||
buffer.appendInt32(615970509)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeString(currency, buffer: buffer, boxed: false)
|
||||
@ -15035,14 +15097,17 @@ public extension Api {
|
||||
for item in prices {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
if Int(flags) & Int(1 << 8) != 0 {serializeInt64(minTipAmount!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 8) != 0 {serializeInt64(maxTipAmount!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 8) != 0 {serializeInt64(defaultTipAmount!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .invoice(let flags, let currency, let prices):
|
||||
return ("invoice", [("flags", flags), ("currency", currency), ("prices", prices)])
|
||||
case .invoice(let flags, let currency, let prices, let minTipAmount, let maxTipAmount, let defaultTipAmount):
|
||||
return ("invoice", [("flags", flags), ("currency", currency), ("prices", prices), ("minTipAmount", minTipAmount), ("maxTipAmount", maxTipAmount), ("defaultTipAmount", defaultTipAmount)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -15055,11 +15120,20 @@ public extension Api {
|
||||
if let _ = reader.readInt32() {
|
||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.LabeledPrice.self)
|
||||
}
|
||||
var _4: Int64?
|
||||
if Int(_1!) & Int(1 << 8) != 0 {_4 = reader.readInt64() }
|
||||
var _5: Int64?
|
||||
if Int(_1!) & Int(1 << 8) != 0 {_5 = reader.readInt64() }
|
||||
var _6: Int64?
|
||||
if Int(_1!) & Int(1 << 8) != 0 {_6 = reader.readInt64() }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
if _c1 && _c2 && _c3 {
|
||||
return Api.Invoice.invoice(flags: _1!, currency: _2!, prices: _3!)
|
||||
let _c4 = (Int(_1!) & Int(1 << 8) == 0) || _4 != nil
|
||||
let _c5 = (Int(_1!) & Int(1 << 8) == 0) || _5 != nil
|
||||
let _c6 = (Int(_1!) & Int(1 << 8) == 0) || _6 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
||||
return Api.Invoice.invoice(flags: _1!, currency: _2!, prices: _3!, minTipAmount: _4, maxTipAmount: _5, defaultTipAmount: _6)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
@ -19173,6 +19247,7 @@ public extension Api {
|
||||
case botInlineMessageMediaGeo(flags: Int32, geo: Api.GeoPoint, heading: Int32?, period: Int32?, proximityNotificationRadius: Int32?, replyMarkup: Api.ReplyMarkup?)
|
||||
case botInlineMessageMediaVenue(flags: Int32, geo: Api.GeoPoint, title: String, address: String, provider: String, venueId: String, venueType: String, replyMarkup: Api.ReplyMarkup?)
|
||||
case botInlineMessageMediaContact(flags: Int32, phoneNumber: String, firstName: String, lastName: String, vcard: String, replyMarkup: Api.ReplyMarkup?)
|
||||
case botInlineMessageMediaInvoice(flags: Int32, title: String, description: String, photo: Api.WebDocument?, currency: String, totalAmount: Int64, replyMarkup: Api.ReplyMarkup?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
@ -19237,6 +19312,18 @@ public extension Api {
|
||||
serializeString(vcard, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)}
|
||||
break
|
||||
case .botInlineMessageMediaInvoice(let flags, let title, let description, let photo, let currency, let totalAmount, let replyMarkup):
|
||||
if boxed {
|
||||
buffer.appendInt32(894081801)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeString(title, buffer: buffer, boxed: false)
|
||||
serializeString(description, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {photo!.serialize(buffer, true)}
|
||||
serializeString(currency, buffer: buffer, boxed: false)
|
||||
serializeInt64(totalAmount, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -19252,6 +19339,8 @@ public extension Api {
|
||||
return ("botInlineMessageMediaVenue", [("flags", flags), ("geo", geo), ("title", title), ("address", address), ("provider", provider), ("venueId", venueId), ("venueType", venueType), ("replyMarkup", replyMarkup)])
|
||||
case .botInlineMessageMediaContact(let flags, let phoneNumber, let firstName, let lastName, let vcard, let replyMarkup):
|
||||
return ("botInlineMessageMediaContact", [("flags", flags), ("phoneNumber", phoneNumber), ("firstName", firstName), ("lastName", lastName), ("vcard", vcard), ("replyMarkup", replyMarkup)])
|
||||
case .botInlineMessageMediaInvoice(let flags, let title, let description, let photo, let currency, let totalAmount, let replyMarkup):
|
||||
return ("botInlineMessageMediaInvoice", [("flags", flags), ("title", title), ("description", description), ("photo", photo), ("currency", currency), ("totalAmount", totalAmount), ("replyMarkup", replyMarkup)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -19397,6 +19486,39 @@ public extension Api {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
public static func parse_botInlineMessageMediaInvoice(_ reader: BufferReader) -> BotInlineMessage? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: String?
|
||||
_2 = parseString(reader)
|
||||
var _3: String?
|
||||
_3 = parseString(reader)
|
||||
var _4: Api.WebDocument?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
|
||||
_4 = Api.parse(reader, signature: signature) as? Api.WebDocument
|
||||
} }
|
||||
var _5: String?
|
||||
_5 = parseString(reader)
|
||||
var _6: Int64?
|
||||
_6 = reader.readInt64()
|
||||
var _7: Api.ReplyMarkup?
|
||||
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
|
||||
_7 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup
|
||||
} }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = _6 != nil
|
||||
let _c7 = (Int(_1!) & Int(1 << 2) == 0) || _7 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
|
||||
return Api.BotInlineMessage.botInlineMessageMediaInvoice(flags: _1!, title: _2!, description: _3!, photo: _4, currency: _5!, totalAmount: _6!, replyMarkup: _7)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public enum InputPeerNotifySettings: TypeConstructorDescription {
|
||||
|
@ -301,15 +301,16 @@ public struct payments {
|
||||
|
||||
}
|
||||
public enum PaymentForm: TypeConstructorDescription {
|
||||
case paymentForm(flags: Int32, botId: Int32, invoice: Api.Invoice, providerId: Int32, url: String, nativeProvider: String?, nativeParams: Api.DataJSON?, savedInfo: Api.PaymentRequestedInfo?, savedCredentials: Api.PaymentSavedCredentials?, users: [Api.User])
|
||||
case paymentForm(flags: Int32, formId: Int64, botId: Int32, invoice: Api.Invoice, providerId: Int32, url: String, nativeProvider: String?, nativeParams: Api.DataJSON?, savedInfo: Api.PaymentRequestedInfo?, savedCredentials: Api.PaymentSavedCredentials?, users: [Api.User])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .paymentForm(let flags, let botId, let invoice, let providerId, let url, let nativeProvider, let nativeParams, let savedInfo, let savedCredentials, let users):
|
||||
case .paymentForm(let flags, let formId, let botId, let invoice, let providerId, let url, let nativeProvider, let nativeParams, let savedInfo, let savedCredentials, let users):
|
||||
if boxed {
|
||||
buffer.appendInt32(1062645411)
|
||||
buffer.appendInt32(-1928649707)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt64(formId, buffer: buffer, boxed: false)
|
||||
serializeInt32(botId, buffer: buffer, boxed: false)
|
||||
invoice.serialize(buffer, true)
|
||||
serializeInt32(providerId, buffer: buffer, boxed: false)
|
||||
@ -329,54 +330,57 @@ public struct payments {
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .paymentForm(let flags, let botId, let invoice, let providerId, let url, let nativeProvider, let nativeParams, let savedInfo, let savedCredentials, let users):
|
||||
return ("paymentForm", [("flags", flags), ("botId", botId), ("invoice", invoice), ("providerId", providerId), ("url", url), ("nativeProvider", nativeProvider), ("nativeParams", nativeParams), ("savedInfo", savedInfo), ("savedCredentials", savedCredentials), ("users", users)])
|
||||
case .paymentForm(let flags, let formId, let botId, let invoice, let providerId, let url, let nativeProvider, let nativeParams, let savedInfo, let savedCredentials, let users):
|
||||
return ("paymentForm", [("flags", flags), ("formId", formId), ("botId", botId), ("invoice", invoice), ("providerId", providerId), ("url", url), ("nativeProvider", nativeProvider), ("nativeParams", nativeParams), ("savedInfo", savedInfo), ("savedCredentials", savedCredentials), ("users", users)])
|
||||
}
|
||||
}
|
||||
|
||||
public static func parse_paymentForm(_ reader: BufferReader) -> PaymentForm? {
|
||||
var _1: Int32?
|
||||
_1 = reader.readInt32()
|
||||
var _2: Int32?
|
||||
_2 = reader.readInt32()
|
||||
var _3: Api.Invoice?
|
||||
var _2: Int64?
|
||||
_2 = reader.readInt64()
|
||||
var _3: Int32?
|
||||
_3 = reader.readInt32()
|
||||
var _4: Api.Invoice?
|
||||
if let signature = reader.readInt32() {
|
||||
_3 = Api.parse(reader, signature: signature) as? Api.Invoice
|
||||
_4 = Api.parse(reader, signature: signature) as? Api.Invoice
|
||||
}
|
||||
var _4: Int32?
|
||||
_4 = reader.readInt32()
|
||||
var _5: String?
|
||||
_5 = parseString(reader)
|
||||
var _5: Int32?
|
||||
_5 = reader.readInt32()
|
||||
var _6: String?
|
||||
if Int(_1!) & Int(1 << 4) != 0 {_6 = parseString(reader) }
|
||||
var _7: Api.DataJSON?
|
||||
_6 = parseString(reader)
|
||||
var _7: String?
|
||||
if Int(_1!) & Int(1 << 4) != 0 {_7 = parseString(reader) }
|
||||
var _8: Api.DataJSON?
|
||||
if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() {
|
||||
_7 = Api.parse(reader, signature: signature) as? Api.DataJSON
|
||||
_8 = Api.parse(reader, signature: signature) as? Api.DataJSON
|
||||
} }
|
||||
var _8: Api.PaymentRequestedInfo?
|
||||
var _9: Api.PaymentRequestedInfo?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() {
|
||||
_8 = Api.parse(reader, signature: signature) as? Api.PaymentRequestedInfo
|
||||
_9 = Api.parse(reader, signature: signature) as? Api.PaymentRequestedInfo
|
||||
} }
|
||||
var _9: Api.PaymentSavedCredentials?
|
||||
var _10: Api.PaymentSavedCredentials?
|
||||
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
|
||||
_9 = Api.parse(reader, signature: signature) as? Api.PaymentSavedCredentials
|
||||
_10 = Api.parse(reader, signature: signature) as? Api.PaymentSavedCredentials
|
||||
} }
|
||||
var _10: [Api.User]?
|
||||
var _11: [Api.User]?
|
||||
if let _ = reader.readInt32() {
|
||||
_10 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||
_11 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = (Int(_1!) & Int(1 << 4) == 0) || _6 != nil
|
||||
let _c6 = _6 != nil
|
||||
let _c7 = (Int(_1!) & Int(1 << 4) == 0) || _7 != nil
|
||||
let _c8 = (Int(_1!) & Int(1 << 0) == 0) || _8 != nil
|
||||
let _c9 = (Int(_1!) & Int(1 << 1) == 0) || _9 != nil
|
||||
let _c10 = _10 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 {
|
||||
return Api.payments.PaymentForm.paymentForm(flags: _1!, botId: _2!, invoice: _3!, providerId: _4!, url: _5!, nativeProvider: _6, nativeParams: _7, savedInfo: _8, savedCredentials: _9, users: _10!)
|
||||
let _c8 = (Int(_1!) & Int(1 << 4) == 0) || _8 != nil
|
||||
let _c9 = (Int(_1!) & Int(1 << 0) == 0) || _9 != nil
|
||||
let _c10 = (Int(_1!) & Int(1 << 1) == 0) || _10 != nil
|
||||
let _c11 = _11 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 {
|
||||
return Api.payments.PaymentForm.paymentForm(flags: _1!, formId: _2!, botId: _3!, invoice: _4!, providerId: _5!, url: _6!, nativeProvider: _7, nativeParams: _8, savedInfo: _9, savedCredentials: _10, users: _11!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -4848,11 +4848,14 @@ public extension Api {
|
||||
}
|
||||
}
|
||||
public struct payments {
|
||||
public static func getPaymentForm(msgId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.PaymentForm>) {
|
||||
public static func getPaymentForm(flags: Int32, peer: Api.InputPeer, msgId: Int32, themeParams: Api.DataJSON?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.PaymentForm>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-1712285883)
|
||||
buffer.appendInt32(-1976353651)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
peer.serialize(buffer, true)
|
||||
serializeInt32(msgId, buffer: buffer, boxed: false)
|
||||
return (FunctionDescription(name: "payments.getPaymentForm", parameters: [("msgId", msgId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.PaymentForm? in
|
||||
if Int(flags) & Int(1 << 0) != 0 {themeParams!.serialize(buffer, true)}
|
||||
return (FunctionDescription(name: "payments.getPaymentForm", parameters: [("flags", flags), ("peer", peer), ("msgId", msgId), ("themeParams", themeParams)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.PaymentForm? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.payments.PaymentForm?
|
||||
if let signature = reader.readInt32() {
|
||||
@ -4862,11 +4865,12 @@ public extension Api {
|
||||
})
|
||||
}
|
||||
|
||||
public static func getPaymentReceipt(msgId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.PaymentReceipt>) {
|
||||
public static func getPaymentReceipt(peer: Api.InputPeer, msgId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.PaymentReceipt>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-1601001088)
|
||||
buffer.appendInt32(611897804)
|
||||
peer.serialize(buffer, true)
|
||||
serializeInt32(msgId, buffer: buffer, boxed: false)
|
||||
return (FunctionDescription(name: "payments.getPaymentReceipt", parameters: [("msgId", msgId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.PaymentReceipt? in
|
||||
return (FunctionDescription(name: "payments.getPaymentReceipt", parameters: [("peer", peer), ("msgId", msgId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.PaymentReceipt? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.payments.PaymentReceipt?
|
||||
if let signature = reader.readInt32() {
|
||||
@ -4876,13 +4880,14 @@ public extension Api {
|
||||
})
|
||||
}
|
||||
|
||||
public static func validateRequestedInfo(flags: Int32, msgId: Int32, info: Api.PaymentRequestedInfo) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.ValidatedRequestedInfo>) {
|
||||
public static func validateRequestedInfo(flags: Int32, peer: Api.InputPeer, msgId: Int32, info: Api.PaymentRequestedInfo) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.ValidatedRequestedInfo>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(1997180532)
|
||||
buffer.appendInt32(-619695760)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
peer.serialize(buffer, true)
|
||||
serializeInt32(msgId, buffer: buffer, boxed: false)
|
||||
info.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "payments.validateRequestedInfo", parameters: [("flags", flags), ("msgId", msgId), ("info", info)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.ValidatedRequestedInfo? in
|
||||
return (FunctionDescription(name: "payments.validateRequestedInfo", parameters: [("flags", flags), ("peer", peer), ("msgId", msgId), ("info", info)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.ValidatedRequestedInfo? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.payments.ValidatedRequestedInfo?
|
||||
if let signature = reader.readInt32() {
|
||||
@ -4892,15 +4897,17 @@ public extension Api {
|
||||
})
|
||||
}
|
||||
|
||||
public static func sendPaymentForm(flags: Int32, msgId: Int32, requestedInfoId: String?, shippingOptionId: String?, credentials: Api.InputPaymentCredentials) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.PaymentResult>) {
|
||||
public static func sendPaymentForm(flags: Int32, formId: Int64, peer: Api.InputPeer, msgId: Int32, requestedInfoId: String?, shippingOptionId: String?, credentials: Api.InputPaymentCredentials) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.PaymentResult>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(730364339)
|
||||
buffer.appendInt32(1940324740)
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt64(formId, buffer: buffer, boxed: false)
|
||||
peer.serialize(buffer, true)
|
||||
serializeInt32(msgId, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeString(requestedInfoId!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 1) != 0 {serializeString(shippingOptionId!, buffer: buffer, boxed: false)}
|
||||
credentials.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "payments.sendPaymentForm", parameters: [("flags", flags), ("msgId", msgId), ("requestedInfoId", requestedInfoId), ("shippingOptionId", shippingOptionId), ("credentials", credentials)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.PaymentResult? in
|
||||
return (FunctionDescription(name: "payments.sendPaymentForm", parameters: [("flags", flags), ("formId", formId), ("peer", peer), ("msgId", msgId), ("requestedInfoId", requestedInfoId), ("shippingOptionId", shippingOptionId), ("credentials", credentials)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.PaymentResult? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.payments.PaymentResult?
|
||||
if let signature = reader.readInt32() {
|
||||
|
@ -37,10 +37,17 @@ public struct BotPaymentPrice : Equatable {
|
||||
}
|
||||
|
||||
public struct BotPaymentInvoice : Equatable {
|
||||
public struct Tip: Equatable {
|
||||
public var min: Int64
|
||||
public var max: Int64
|
||||
public var `default`: Int64
|
||||
}
|
||||
|
||||
public let isTest: Bool
|
||||
public let requestedFields: BotPaymentInvoiceFields
|
||||
public let currency: String
|
||||
public let prices: [BotPaymentPrice]
|
||||
public let tip: Tip?
|
||||
}
|
||||
|
||||
public struct BotPaymentNativeProvider : Equatable {
|
||||
@ -67,16 +74,18 @@ public struct BotPaymentShippingAddress: Equatable {
|
||||
}
|
||||
|
||||
public struct BotPaymentRequestedInfo: Equatable {
|
||||
public let name: String?
|
||||
public let phone: String?
|
||||
public let email: String?
|
||||
public let shippingAddress: BotPaymentShippingAddress?
|
||||
public var name: String?
|
||||
public var phone: String?
|
||||
public var email: String?
|
||||
public var shippingAddress: BotPaymentShippingAddress?
|
||||
public var tipAmount: Int64?
|
||||
|
||||
public init(name: String?, phone: String?, email: String?, shippingAddress: BotPaymentShippingAddress?) {
|
||||
public init(name: String?, phone: String?, email: String?, shippingAddress: BotPaymentShippingAddress?, tipAmount: Int64?) {
|
||||
self.name = name
|
||||
self.phone = phone
|
||||
self.email = email
|
||||
self.shippingAddress = shippingAddress
|
||||
self.tipAmount = tipAmount
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,6 +105,7 @@ public enum BotPaymentSavedCredentials: Equatable {
|
||||
}
|
||||
|
||||
public struct BotPaymentForm : Equatable {
|
||||
public let id: Int64
|
||||
public let canSaveCredentials: Bool
|
||||
public let passwordMissing: Bool
|
||||
public let invoice: BotPaymentInvoice
|
||||
@ -113,7 +123,7 @@ public enum BotPaymentFormRequestError {
|
||||
extension BotPaymentInvoice {
|
||||
init(apiInvoice: Api.Invoice) {
|
||||
switch apiInvoice {
|
||||
case let .invoice(flags, currency, prices):
|
||||
case let .invoice(flags, currency, prices, minTipAmount, maxTipAmount, defaultTipAmount):
|
||||
var fields = BotPaymentInvoiceFields()
|
||||
if (flags & (1 << 1)) != 0 {
|
||||
fields.insert(.name)
|
||||
@ -136,12 +146,16 @@ extension BotPaymentInvoice {
|
||||
if (flags & (1 << 7)) != 0 {
|
||||
fields.insert(.emailAvailableToProvider)
|
||||
}
|
||||
var parsedTip: BotPaymentInvoice.Tip?
|
||||
if let minTipAmount = minTipAmount, let maxTipAmount = maxTipAmount, let defaultTipAmount = defaultTipAmount {
|
||||
parsedTip = BotPaymentInvoice.Tip(min: minTipAmount, max: maxTipAmount, default: defaultTipAmount)
|
||||
}
|
||||
self.init(isTest: (flags & (1 << 0)) != 0, requestedFields: fields, currency: currency, prices: prices.map {
|
||||
switch $0 {
|
||||
case let .labeledPrice(label, amount):
|
||||
return BotPaymentPrice(label: label, amount: amount)
|
||||
}
|
||||
})
|
||||
}, tip: parsedTip)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,7 +163,7 @@ extension BotPaymentInvoice {
|
||||
extension BotPaymentRequestedInfo {
|
||||
init(apiInfo: Api.PaymentRequestedInfo) {
|
||||
switch apiInfo {
|
||||
case let .paymentRequestedInfo(_, name, phone, email, shippingAddress):
|
||||
case let .paymentRequestedInfo(_, name, phone, email, shippingAddress, tipAmount):
|
||||
var parsedShippingAddress: BotPaymentShippingAddress?
|
||||
if let shippingAddress = shippingAddress {
|
||||
switch shippingAddress {
|
||||
@ -157,20 +171,28 @@ extension BotPaymentRequestedInfo {
|
||||
parsedShippingAddress = BotPaymentShippingAddress(streetLine1: streetLine1, streetLine2: streetLine2, city: city, state: state, countryIso2: countryIso2, postCode: postCode)
|
||||
}
|
||||
}
|
||||
self.init(name: name, phone: phone, email: email, shippingAddress: parsedShippingAddress)
|
||||
self.init(name: name, phone: phone, email: email, shippingAddress: parsedShippingAddress, tipAmount: tipAmount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func fetchBotPaymentForm(postbox: Postbox, network: Network, messageId: MessageId) -> Signal<BotPaymentForm, BotPaymentFormRequestError> {
|
||||
return network.request(Api.functions.payments.getPaymentForm(msgId: messageId.id))
|
||||
return postbox.transaction { transaction -> Api.InputPeer? in
|
||||
return transaction.getPeer(messageId.peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
|> castError(BotPaymentFormRequestError.self)
|
||||
|> mapToSignal { inputPeer -> Signal<BotPaymentForm, BotPaymentFormRequestError> in
|
||||
guard let inputPeer = inputPeer else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
return network.request(Api.functions.payments.getPaymentForm(flags: 0, peer: inputPeer, msgId: messageId.id, themeParams: nil))
|
||||
|> `catch` { _ -> Signal<Api.payments.PaymentForm, BotPaymentFormRequestError> in
|
||||
return .fail(.generic)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<BotPaymentForm, BotPaymentFormRequestError> in
|
||||
return postbox.transaction { transaction -> BotPaymentForm in
|
||||
switch result {
|
||||
case let .paymentForm(flags, _, invoice, providerId, url, nativeProvider, nativeParams, savedInfo, savedCredentials, apiUsers):
|
||||
case let .paymentForm(flags, id, _, invoice, providerId, url, nativeProvider, nativeParams, savedInfo, savedCredentials, apiUsers):
|
||||
var peers: [Peer] = []
|
||||
for user in apiUsers {
|
||||
let parsed = TelegramUser(user: user)
|
||||
@ -179,7 +201,7 @@ public func fetchBotPaymentForm(postbox: Postbox, network: Network, messageId: M
|
||||
updatePeers(transaction: transaction, peers: peers, update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
|
||||
|
||||
let parsedInvoice = BotPaymentInvoice(apiInvoice: invoice)
|
||||
var parsedNativeProvider: BotPaymentNativeProvider?
|
||||
if let nativeProvider = nativeProvider, let nativeParams = nativeParams {
|
||||
@ -196,10 +218,12 @@ public func fetchBotPaymentForm(postbox: Postbox, network: Network, messageId: M
|
||||
parsedSavedCredentials = .card(id: id, title: title)
|
||||
}
|
||||
}
|
||||
return BotPaymentForm(canSaveCredentials: (flags & (1 << 2)) != 0, passwordMissing: (flags & (1 << 3)) != 0, invoice: parsedInvoice, providerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: providerId), url: url, nativeProvider: parsedNativeProvider, savedInfo: parsedSavedInfo, savedCredentials: parsedSavedCredentials)
|
||||
return BotPaymentForm(id: id, canSaveCredentials: (flags & (1 << 2)) != 0, passwordMissing: (flags & (1 << 3)) != 0, invoice: parsedInvoice, providerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: providerId), url: url, nativeProvider: parsedNativeProvider, savedInfo: parsedSavedInfo, savedCredentials: parsedSavedCredentials)
|
||||
}
|
||||
} |> mapError { _ -> BotPaymentFormRequestError in return .generic }
|
||||
}
|
||||
|> mapError { _ -> BotPaymentFormRequestError in }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ValidateBotPaymentFormError {
|
||||
@ -238,27 +262,39 @@ extension BotPaymentShippingOption {
|
||||
}
|
||||
}
|
||||
|
||||
public func validateBotPaymentForm(network: Network, saveInfo: Bool, messageId: MessageId, formInfo: BotPaymentRequestedInfo) -> Signal<BotPaymentValidatedFormInfo, ValidateBotPaymentFormError> {
|
||||
var flags: Int32 = 0
|
||||
if saveInfo {
|
||||
flags |= (1 << 0)
|
||||
public func validateBotPaymentForm(account: Account, saveInfo: Bool, messageId: MessageId, formInfo: BotPaymentRequestedInfo) -> Signal<BotPaymentValidatedFormInfo, ValidateBotPaymentFormError> {
|
||||
return account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||
return transaction.getPeer(messageId.peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
var infoFlags: Int32 = 0
|
||||
if let _ = formInfo.name {
|
||||
infoFlags |= (1 << 0)
|
||||
}
|
||||
if let _ = formInfo.phone {
|
||||
infoFlags |= (1 << 1)
|
||||
}
|
||||
if let _ = formInfo.email {
|
||||
infoFlags |= (1 << 2)
|
||||
}
|
||||
var apiShippingAddress: Api.PostAddress?
|
||||
if let address = formInfo.shippingAddress {
|
||||
infoFlags |= (1 << 3)
|
||||
apiShippingAddress = .postAddress(streetLine1: address.streetLine1, streetLine2: address.streetLine2, city: address.city, state: address.state, countryIso2: address.countryIso2, postCode: address.postCode)
|
||||
}
|
||||
return network.request(Api.functions.payments.validateRequestedInfo(flags: flags, msgId: messageId.id, info: .paymentRequestedInfo(flags: infoFlags, name: formInfo.name, phone: formInfo.phone, email: formInfo.email, shippingAddress: apiShippingAddress)))
|
||||
|> castError(ValidateBotPaymentFormError.self)
|
||||
|> mapToSignal { inputPeer -> Signal<BotPaymentValidatedFormInfo, ValidateBotPaymentFormError> in
|
||||
guard let inputPeer = inputPeer else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
var flags: Int32 = 0
|
||||
if saveInfo {
|
||||
flags |= (1 << 0)
|
||||
}
|
||||
var infoFlags: Int32 = 0
|
||||
if let _ = formInfo.name {
|
||||
infoFlags |= (1 << 0)
|
||||
}
|
||||
if let _ = formInfo.phone {
|
||||
infoFlags |= (1 << 1)
|
||||
}
|
||||
if let _ = formInfo.email {
|
||||
infoFlags |= (1 << 2)
|
||||
}
|
||||
var apiShippingAddress: Api.PostAddress?
|
||||
if let address = formInfo.shippingAddress {
|
||||
infoFlags |= (1 << 3)
|
||||
apiShippingAddress = .postAddress(streetLine1: address.streetLine1, streetLine2: address.streetLine2, city: address.city, state: address.state, countryIso2: address.countryIso2, postCode: address.postCode)
|
||||
}
|
||||
if let _ = formInfo.tipAmount {
|
||||
infoFlags |= (1 << 4)
|
||||
}
|
||||
return account.network.request(Api.functions.payments.validateRequestedInfo(flags: flags, peer: inputPeer, msgId: messageId.id, info: .paymentRequestedInfo(flags: infoFlags, name: formInfo.name, phone: formInfo.phone, email: formInfo.email, shippingAddress: apiShippingAddress, tipAmount: formInfo.tipAmount)))
|
||||
|> mapError { error -> ValidateBotPaymentFormError in
|
||||
if error.errorDescription == "SHIPPING_NOT_AVAILABLE" {
|
||||
return .shippingNotAvailable
|
||||
@ -286,6 +322,7 @@ public func validateBotPaymentForm(network: Network, saveInfo: Bool, messageId:
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum BotPaymentCredentials {
|
||||
@ -306,46 +343,56 @@ public enum SendBotPaymentResult {
|
||||
case externalVerificationRequired(url: String)
|
||||
}
|
||||
|
||||
public func sendBotPaymentForm(account: Account, messageId: MessageId, validatedInfoId: String?, shippingOptionId: String?, credentials: BotPaymentCredentials) -> Signal<SendBotPaymentResult, SendBotPaymentFormError> {
|
||||
let apiCredentials: Api.InputPaymentCredentials
|
||||
switch credentials {
|
||||
case let .generic(data, saveOnServer):
|
||||
var credentialsFlags: Int32 = 0
|
||||
if saveOnServer {
|
||||
credentialsFlags |= (1 << 0)
|
||||
public func sendBotPaymentForm(account: Account, messageId: MessageId, formId: Int64, validatedInfoId: String?, shippingOptionId: String?, credentials: BotPaymentCredentials) -> Signal<SendBotPaymentResult, SendBotPaymentFormError> {
|
||||
return account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||
return transaction.getPeer(messageId.peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
|> castError(SendBotPaymentFormError.self)
|
||||
|> mapToSignal { inputPeer -> Signal<SendBotPaymentResult, SendBotPaymentFormError> in
|
||||
guard let inputPeer = inputPeer else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
let apiCredentials: Api.InputPaymentCredentials
|
||||
switch credentials {
|
||||
case let .generic(data, saveOnServer):
|
||||
var credentialsFlags: Int32 = 0
|
||||
if saveOnServer {
|
||||
credentialsFlags |= (1 << 0)
|
||||
}
|
||||
apiCredentials = .inputPaymentCredentials(flags: credentialsFlags, data: .dataJSON(data: data))
|
||||
case let .saved(id, tempPassword):
|
||||
apiCredentials = .inputPaymentCredentialsSaved(id: id, tmpPassword: Buffer(data: tempPassword))
|
||||
case let .applePay(data):
|
||||
apiCredentials = .inputPaymentCredentialsApplePay(paymentData: .dataJSON(data: data))
|
||||
}
|
||||
var flags: Int32 = 0
|
||||
if validatedInfoId != nil {
|
||||
flags |= (1 << 0)
|
||||
}
|
||||
if shippingOptionId != nil {
|
||||
flags |= (1 << 1)
|
||||
}
|
||||
return account.network.request(Api.functions.payments.sendPaymentForm(flags: flags, formId: formId, peer: inputPeer, msgId: messageId.id, requestedInfoId: validatedInfoId, shippingOptionId: shippingOptionId, credentials: apiCredentials))
|
||||
|> map { result -> SendBotPaymentResult in
|
||||
switch result {
|
||||
case let .paymentResult(updates):
|
||||
account.stateManager.addUpdates(updates)
|
||||
return .done
|
||||
case let .paymentVerificationNeeded(url):
|
||||
return .externalVerificationRequired(url: url)
|
||||
}
|
||||
apiCredentials = .inputPaymentCredentials(flags: credentialsFlags, data: .dataJSON(data: data))
|
||||
case let .saved(id, tempPassword):
|
||||
apiCredentials = .inputPaymentCredentialsSaved(id: id, tmpPassword: Buffer(data: tempPassword))
|
||||
case let .applePay(data):
|
||||
apiCredentials = .inputPaymentCredentialsApplePay(paymentData: .dataJSON(data: data))
|
||||
}
|
||||
var flags: Int32 = 0
|
||||
if validatedInfoId != nil {
|
||||
flags |= (1 << 0)
|
||||
}
|
||||
if shippingOptionId != nil {
|
||||
flags |= (1 << 1)
|
||||
}
|
||||
return account.network.request(Api.functions.payments.sendPaymentForm(flags: flags, msgId: messageId.id, requestedInfoId: validatedInfoId, shippingOptionId: shippingOptionId, credentials: apiCredentials))
|
||||
|> map { result -> SendBotPaymentResult in
|
||||
switch result {
|
||||
case let .paymentResult(updates):
|
||||
account.stateManager.addUpdates(updates)
|
||||
return .done
|
||||
case let .paymentVerificationNeeded(url):
|
||||
return .externalVerificationRequired(url: url)
|
||||
}
|
||||
}
|
||||
|> `catch` { error -> Signal<SendBotPaymentResult, SendBotPaymentFormError> in
|
||||
if error.errorDescription == "BOT_PRECHECKOUT_FAILED" {
|
||||
return .fail(.precheckoutFailed)
|
||||
} else if error.errorDescription == "PAYMENT_FAILED" {
|
||||
return .fail(.paymentFailed)
|
||||
} else if error.errorDescription == "INVOICE_ALREADY_PAID" {
|
||||
return .fail(.alreadyPaid)
|
||||
|> `catch` { error -> Signal<SendBotPaymentResult, SendBotPaymentFormError> in
|
||||
if error.errorDescription == "BOT_PRECHECKOUT_FAILED" {
|
||||
return .fail(.precheckoutFailed)
|
||||
} else if error.errorDescription == "PAYMENT_FAILED" {
|
||||
return .fail(.paymentFailed)
|
||||
} else if error.errorDescription == "INVOICE_ALREADY_PAID" {
|
||||
return .fail(.alreadyPaid)
|
||||
}
|
||||
return .fail(.generic)
|
||||
}
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,16 +403,32 @@ public struct BotPaymentReceipt : Equatable {
|
||||
public let credentialsTitle: String
|
||||
}
|
||||
|
||||
public func requestBotPaymentReceipt(network: Network, messageId: MessageId) -> Signal<BotPaymentReceipt, NoError> {
|
||||
return network.request(Api.functions.payments.getPaymentReceipt(msgId: messageId.id))
|
||||
|> retryRequest
|
||||
|> map { result -> BotPaymentReceipt in
|
||||
switch result {
|
||||
case let .paymentReceipt(_, _, _, invoice, _, info, shipping, _, _, credentialsTitle, _):
|
||||
let parsedInvoice = BotPaymentInvoice(apiInvoice: invoice)
|
||||
let parsedInfo = info.flatMap(BotPaymentRequestedInfo.init)
|
||||
let shippingOption = shipping.flatMap(BotPaymentShippingOption.init)
|
||||
return BotPaymentReceipt(invoice: parsedInvoice, info: parsedInfo, shippingOption: shippingOption, credentialsTitle: credentialsTitle)
|
||||
public enum RequestBotPaymentReceiptError {
|
||||
case generic
|
||||
}
|
||||
|
||||
public func requestBotPaymentReceipt(account: Account, messageId: MessageId) -> Signal<BotPaymentReceipt, RequestBotPaymentReceiptError> {
|
||||
return account.postbox.transaction { transaction -> Api.InputPeer? in
|
||||
return transaction.getPeer(messageId.peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
|> castError(RequestBotPaymentReceiptError.self)
|
||||
|> mapToSignal { inputPeer -> Signal<BotPaymentReceipt, RequestBotPaymentReceiptError> in
|
||||
guard let inputPeer = inputPeer else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
return account.network.request(Api.functions.payments.getPaymentReceipt(peer: inputPeer, msgId: messageId.id))
|
||||
|> mapError { _ -> RequestBotPaymentReceiptError in
|
||||
return .generic
|
||||
}
|
||||
|> map { result -> BotPaymentReceipt in
|
||||
switch result {
|
||||
case let .paymentReceipt(_, _, _, invoice, _, info, shipping, _, _, credentialsTitle, _):
|
||||
let parsedInvoice = BotPaymentInvoice(apiInvoice: invoice)
|
||||
let parsedInfo = info.flatMap(BotPaymentRequestedInfo.init)
|
||||
let shippingOption = shipping.flatMap(BotPaymentShippingOption.init)
|
||||
return BotPaymentReceipt(invoice: parsedInvoice, info: parsedInfo, shippingOption: shippingOption, credentialsTitle: credentialsTitle)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ public enum ChatContextResultMessage: PostboxCoding, Equatable, Codable {
|
||||
case text(text: String, entities: TextEntitiesMessageAttribute?, disableUrlPreview: Bool, replyMarkup: ReplyMarkupMessageAttribute?)
|
||||
case mapLocation(media: TelegramMediaMap, replyMarkup: ReplyMarkupMessageAttribute?)
|
||||
case contact(media: TelegramMediaContact, replyMarkup: ReplyMarkupMessageAttribute?)
|
||||
case invoice(media: TelegramMediaInvoice, replyMarkup: ReplyMarkupMessageAttribute?)
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
switch decoder.decodeInt32ForKey("_v", orElse: 0) {
|
||||
@ -30,6 +31,8 @@ public enum ChatContextResultMessage: PostboxCoding, Equatable, Codable {
|
||||
self = .mapLocation(media: decoder.decodeObjectForKey("l") as! TelegramMediaMap, replyMarkup: decoder.decodeObjectForKey("m") as? ReplyMarkupMessageAttribute)
|
||||
case 3:
|
||||
self = .contact(media: decoder.decodeObjectForKey("c") as! TelegramMediaContact, replyMarkup: decoder.decodeObjectForKey("m") as? ReplyMarkupMessageAttribute)
|
||||
case 4:
|
||||
self = .invoice(media: decoder.decodeObjectForKey("i") as! TelegramMediaInvoice, replyMarkup: decoder.decodeObjectForKey("m") as? ReplyMarkupMessageAttribute)
|
||||
default:
|
||||
self = .auto(caption: "", entities: nil, replyMarkup: nil)
|
||||
}
|
||||
@ -80,6 +83,14 @@ public enum ChatContextResultMessage: PostboxCoding, Equatable, Codable {
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "m")
|
||||
}
|
||||
case let .invoice(media: media, replyMarkup):
|
||||
encoder.encodeInt32(4, forKey: "_v")
|
||||
encoder.encodeObject(media, forKey: "i")
|
||||
if let replyMarkup = replyMarkup {
|
||||
encoder.encodeObject(replyMarkup, forKey: "m")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "m")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,6 +168,18 @@ public enum ChatContextResultMessage: PostboxCoding, Equatable, Codable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .invoice(lhsMedia, lhsReplyMarkup):
|
||||
if case let .invoice(rhsMedia, rhsReplyMarkup) = rhs {
|
||||
if !lhsMedia.isEqual(to: rhsMedia) {
|
||||
return false
|
||||
}
|
||||
if lhsReplyMarkup != rhsReplyMarkup {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -444,6 +467,19 @@ extension ChatContextResultMessage {
|
||||
parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup)
|
||||
}
|
||||
self = .contact(media: media, replyMarkup: parsedReplyMarkup)
|
||||
case let .botInlineMessageMediaInvoice(flags, title, description, photo, currency, totalAmount, replyMarkup):
|
||||
var parsedFlags = TelegramMediaInvoiceFlags()
|
||||
if (flags & (1 << 3)) != 0 {
|
||||
parsedFlags.insert(.isTest)
|
||||
}
|
||||
if (flags & (1 << 1)) != 0 {
|
||||
parsedFlags.insert(.shippingAddressRequested)
|
||||
}
|
||||
var parsedReplyMarkup: ReplyMarkupMessageAttribute?
|
||||
if let replyMarkup = replyMarkup {
|
||||
parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup)
|
||||
}
|
||||
self = .invoice(media: TelegramMediaInvoice(title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init), receiptMessageId: nil, currency: currency, totalAmount: totalAmount, startParam: "", flags: parsedFlags), replyMarkup: parsedReplyMarkup)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +110,8 @@ public func getCurrentGroupCall(account: Account, callId: Int64, accessHash: Int
|
||||
|
||||
loop: for participant in participants {
|
||||
switch participant {
|
||||
case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, params):
|
||||
case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating/*, params*/):
|
||||
let params: Api.DataJSON? = nil
|
||||
let peerId: PeerId
|
||||
switch apiPeerId {
|
||||
case let .peerUser(userId):
|
||||
@ -297,7 +298,8 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash
|
||||
|
||||
loop: for participant in participants {
|
||||
switch participant {
|
||||
case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, params):
|
||||
case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating/*, params*/):
|
||||
let params: Api.DataJSON? = nil
|
||||
let peerId: PeerId
|
||||
switch apiPeerId {
|
||||
case let .peerUser(userId):
|
||||
@ -545,7 +547,8 @@ public func joinGroupCall(account: Account, peerId: PeerId, joinAs: PeerId?, cal
|
||||
case let .updateGroupCallParticipants(_, participants, _):
|
||||
loop: for participant in participants {
|
||||
switch participant {
|
||||
case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, params):
|
||||
case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating/*, params*/):
|
||||
let params: Api.DataJSON? = nil
|
||||
let peerId: PeerId
|
||||
switch apiPeerId {
|
||||
case let .peerUser(userId):
|
||||
@ -1751,7 +1754,8 @@ public final class GroupCallParticipantsContext {
|
||||
extension GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate {
|
||||
init(_ apiParticipant: Api.GroupCallParticipant) {
|
||||
switch apiParticipant {
|
||||
case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, params):
|
||||
case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating/*, params*/):
|
||||
let params: Api.DataJSON? = nil
|
||||
let peerId: PeerId
|
||||
switch apiPeerId {
|
||||
case let .peerUser(userId):
|
||||
@ -1814,7 +1818,8 @@ extension GroupCallParticipantsContext.Update.StateUpdate {
|
||||
var participantUpdates: [GroupCallParticipantsContext.Update.StateUpdate.ParticipantUpdate] = []
|
||||
for participant in participants {
|
||||
switch participant {
|
||||
case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating, params):
|
||||
case let .groupCallParticipant(flags, apiPeerId, date, activeDate, source, volume, about, raiseHandRating/*, params*/):
|
||||
let params: Api.DataJSON? = nil
|
||||
let peerId: PeerId
|
||||
switch apiPeerId {
|
||||
case let .peerUser(userId):
|
||||
|
@ -141,5 +141,10 @@ public func outgoingMessageWithChatContextResult(to peerId: PeerId, results: Cha
|
||||
attributes.append(replyMarkup)
|
||||
}
|
||||
return .message(text: "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil)
|
||||
case let .invoice(media, replyMarkup):
|
||||
if let replyMarkup = replyMarkup {
|
||||
attributes.append(replyMarkup)
|
||||
}
|
||||
return .message(text: "", attributes: attributes, mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil)
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,28 @@ private func loadCurrencyFormatterEntries() -> [String: CurrencyFormatterEntry]
|
||||
|
||||
private let currencyFormatterEntries = loadCurrencyFormatterEntries()
|
||||
|
||||
public func fractionalToCurrencyAmount(value: Double, currency: String) -> Int64? {
|
||||
guard let entry = currencyFormatterEntries[currency] ?? currencyFormatterEntries["USD"] else {
|
||||
return nil
|
||||
}
|
||||
var factor: Double = 1.0
|
||||
for _ in 0 ..< entry.decimalDigits {
|
||||
factor *= 10.0
|
||||
}
|
||||
return Int64(value * factor)
|
||||
}
|
||||
|
||||
public func currencyToFractionalAmount(value: Int64, currency: String) -> Double? {
|
||||
guard let entry = currencyFormatterEntries[currency] ?? currencyFormatterEntries["USD"] else {
|
||||
return nil
|
||||
}
|
||||
var factor: Double = 1.0
|
||||
for _ in 0 ..< entry.decimalDigits {
|
||||
factor *= 10.0
|
||||
}
|
||||
return Double(value) / factor
|
||||
}
|
||||
|
||||
public func formatCurrencyAmount(_ amount: Int64, currency: String) -> String {
|
||||
if let entry = currencyFormatterEntries[currency] ?? currencyFormatterEntries["USD"] {
|
||||
var result = ""
|
||||
|
@ -619,6 +619,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if canSetupAutoremoveTimeout {
|
||||
strongSelf.presentAutoremoveSetup()
|
||||
}
|
||||
case .paymentSent:
|
||||
for attribute in message.attributes {
|
||||
if let attribute = attribute as? ReplyMessageAttribute {
|
||||
strongSelf.navigateToMessage(from: message.id, to: .id(attribute.messageId))
|
||||
break
|
||||
}
|
||||
}
|
||||
return true
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user