mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-06 17:00:13 +00:00
Merge branches 'master' and 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
045d102294
@ -2552,7 +2552,6 @@ Unused sets are archived when you add more.";
|
||||
"Message.ForwardedMessageShort" = "Forwarded From\n%@";
|
||||
|
||||
"Checkout.LiabilityAlertTitle" = "Warning";
|
||||
"Checkout.LiabilityAlert" = "Neither Telegram, nor %1$@ will have access to your credit card information. Credit card details will be handled only by the payment system, %2$@.\n\nPayments will go directly to the developer of %1$@. Telegram cannot provide any guarantees, so proceed at your own risk. In case of problems, please contact the developer of %1$@ or your bank.";
|
||||
|
||||
"Settings.AppLanguage" = "Language";
|
||||
"Settings.AppLanguage.Unofficial" = "UNOFFICIAL";
|
||||
@ -6430,3 +6429,9 @@ Sorry for the inconvenience.";
|
||||
"ScheduledIn.Years_3_10" = "%@ years";
|
||||
"ScheduledIn.Years_any" = "%@ years";
|
||||
"ScheduledIn.Months_many" = "%@ years";
|
||||
|
||||
"Checkout.PaymentLiabilityAlert" = "Neither Telegram, nor {target} will have access to your credit card information. Credit card details will be handled only by the payment system, {payment_system}.\n\nPayments will go directly to the developer of {target}. Telegram cannot provide any guarantees, so proceed at your own risk. In case of problems, please contact the developer of {target} or your bank.";
|
||||
|
||||
"Checkout.OptionalTipItem" = "Tip (Optional)";
|
||||
"Checkout.TipItem" = "Tip";
|
||||
"Checkout.OptionalTipItemPlaceholder" = "Enter Custom";
|
||||
|
||||
@ -329,8 +329,7 @@ private func botCheckoutControllerEntries(presentationData: PresentationData, st
|
||||
|
||||
if let tip = paymentForm.invoice.tip {
|
||||
let tipTitle: String
|
||||
//TODO:localize
|
||||
tipTitle = "Tip (Optional)"
|
||||
tipTitle = presentationData.strings.Checkout_OptionalTipItem
|
||||
entries.append(.tip(index, presentationData.theme, tipTitle, paymentForm.invoice.currency, "\(formatCurrencyAmount(currentTip ?? 0, currency: paymentForm.invoice.currency))", currentTip ?? 0, tip.max, tip.suggested.map { item -> (String, Int64) in
|
||||
return ("\(formatCurrencyAmount(item, currency: paymentForm.invoice.currency))", item)
|
||||
}))
|
||||
@ -471,6 +470,9 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
private let paymentAuthDisposable = MetaDisposable()
|
||||
private var applePayAuthrorizationCompletion: ((PKPaymentAuthorizationStatus) -> Void)?
|
||||
private var applePayController: PKPaymentAuthorizationViewController?
|
||||
|
||||
private var passwordTip: String?
|
||||
private var passwordTipDisposable: Disposable?
|
||||
|
||||
init(controller: BotCheckoutController?, navigationBar: NavigationBar, updateNavigationOffset: @escaping (CGFloat) -> Void, context: AccountContext, invoice: TelegramMediaInvoice, messageId: MessageId, present: @escaping (ViewController, Any?) -> Void, dismissAnimated: @escaping () -> Void) {
|
||||
self.controller = controller
|
||||
@ -826,8 +828,15 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
}), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}
|
||||
}
|
||||
let themeParams: [String: Any] = [
|
||||
"bg_color": Int32(bitPattern: self.presentationData.theme.list.plainBackgroundColor.argb),
|
||||
"text_color": Int32(bitPattern: self.presentationData.theme.list.itemPrimaryTextColor.argb),
|
||||
"link_color": Int32(bitPattern: self.presentationData.theme.list.itemAccentColor.argb),
|
||||
"button_color": Int32(bitPattern: self.presentationData.theme.list.itemCheckColors.fillColor.argb),
|
||||
"button_text_color": Int32(bitPattern: self.presentationData.theme.list.itemCheckColors.foregroundColor.argb)
|
||||
]
|
||||
|
||||
let formAndMaybeValidatedInfo = fetchBotPaymentForm(postbox: context.account.postbox, network: context.account.network, messageId: messageId)
|
||||
let formAndMaybeValidatedInfo = fetchBotPaymentForm(postbox: context.account.postbox, network: context.account.network, messageId: messageId, themeParams: themeParams)
|
||||
|> mapToSignal { paymentForm -> Signal<(BotPaymentForm, BotPaymentValidatedFormInfo?), BotPaymentFormRequestError> in
|
||||
if let current = paymentForm.savedInfo {
|
||||
return validateBotPaymentForm(account: context.account, saveInfo: true, messageId: messageId, formInfo: current)
|
||||
@ -879,12 +888,28 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
self.actionButton.isEnabled = false
|
||||
|
||||
self.listNode.supernode?.insertSubnode(self.inProgressDimNode, aboveSubnode: self.listNode)
|
||||
|
||||
self.passwordTipDisposable = (twoStepVerificationConfiguration(account: self.context.account)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
switch value {
|
||||
case .notSet:
|
||||
break
|
||||
case let .set(hint, _, _, _):
|
||||
if !hint.isEmpty {
|
||||
strongSelf.passwordTip = hint
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.formRequestDisposable?.dispose()
|
||||
self.payDisposable.dispose()
|
||||
self.paymentAuthDisposable.dispose()
|
||||
self.passwordTipDisposable?.dispose()
|
||||
}
|
||||
|
||||
private func updateActionButton() {
|
||||
@ -1083,10 +1108,9 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
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))
|
||||
items.append(PKPaymentSummaryItem(label: strongSelf.presentationData.strings.Checkout_TipItem, amount: amount))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1126,7 +1150,11 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
if value {
|
||||
strongSelf.pay(savedCredentialsToken: savedCredentialsToken, liabilityNoticeAccepted: true)
|
||||
} else {
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: strongSelf.presentationData.strings.Checkout_LiabilityAlertTitle, text: strongSelf.presentationData.strings.Checkout_LiabilityAlert(botPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), providerPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: { }), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {
|
||||
let paymentText = strongSelf.presentationData.strings.Checkout_PaymentLiabilityAlert
|
||||
.replacingOccurrences(of: "{target}", with: botPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
.replacingOccurrences(of: "{payment_system}", with: providerPeer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: strongSelf.presentationData.strings.Checkout_LiabilityAlertTitle, text: paymentText, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: { }), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {
|
||||
if let strongSelf = self {
|
||||
let _ = ApplicationSpecificNotice.setBotPaymentLiability(accountManager: strongSelf.context.sharedContext.accountManager, peerId: strongSelf.messageId.peerId).start()
|
||||
strongSelf.pay(savedCredentialsToken: savedCredentialsToken, liabilityNoticeAccepted: true)
|
||||
@ -1222,7 +1250,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
period = 1 * 60 * 60
|
||||
requiresBiometrics = false
|
||||
}
|
||||
self.present(botCheckoutPasswordEntryController(context: self.context, strings: self.presentationData.strings, cartTitle: cardTitle, period: period, requiresBiometrics: requiresBiometrics, completion: { [weak self] token in
|
||||
self.present(botCheckoutPasswordEntryController(context: self.context, strings: self.presentationData.strings, passwordTip: self.passwordTip, cartTitle: cardTitle, period: period, requiresBiometrics: requiresBiometrics, completion: { [weak self] token in
|
||||
if let strongSelf = self {
|
||||
let durationString = timeIntervalString(strings: strongSelf.presentationData.strings, value: period)
|
||||
|
||||
|
||||
@ -94,7 +94,7 @@ private final class BotCheckoutPasswordAlertContentNode: AlertContentNode {
|
||||
|
||||
private let hapticFeedback = HapticFeedback()
|
||||
|
||||
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, cardTitle: String, period: Int32, requiresBiometrics: Bool, cancel: @escaping () -> Void, completion: @escaping (TemporaryTwoStepPasswordToken) -> Void) {
|
||||
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, passwordTip: String?, cardTitle: String, period: Int32, requiresBiometrics: Bool, cancel: @escaping () -> Void, completion: @escaping (TemporaryTwoStepPasswordToken) -> Void) {
|
||||
self.context = context
|
||||
self.period = period
|
||||
self.requiresBiometrics = requiresBiometrics
|
||||
@ -156,6 +156,8 @@ private final class BotCheckoutPasswordAlertContentNode: AlertContentNode {
|
||||
self.textFieldNode.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
|
||||
self.textFieldNode.textField.isSecureTextEntry = true
|
||||
self.textFieldNode.textField.tintColor = theme.list.itemAccentColor
|
||||
self.textFieldNode.textField.placeholder = passwordTip
|
||||
|
||||
|
||||
super.init()
|
||||
|
||||
@ -218,7 +220,7 @@ private final class BotCheckoutPasswordAlertContentNode: AlertContentNode {
|
||||
|
||||
let textFieldBackgroundFrame = CGRect(origin: CGPoint(x: insets.left, y: resultSize.height - inputHeight + 12.0 - actionsHeight - insets.bottom), size: CGSize(width: resultSize.width - insets.left - insets.right, height: 25.0))
|
||||
self.textFieldNodeBackground.frame = textFieldBackgroundFrame
|
||||
self.textFieldNode.frame = textFieldBackgroundFrame.offsetBy(dx: 0.0, dy: 1.0).insetBy(dx: 4.0, dy: 0.0)
|
||||
self.textFieldNode.frame = textFieldBackgroundFrame.offsetBy(dx: 0.0, dy: 0.0).insetBy(dx: 4.0, dy: 0.0)
|
||||
|
||||
self.actionNodesSeparator.frame = CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel))
|
||||
|
||||
@ -300,10 +302,10 @@ private final class BotCheckoutPasswordAlertContentNode: AlertContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
func botCheckoutPasswordEntryController(context: AccountContext, strings: PresentationStrings, cartTitle: String, period: Int32, requiresBiometrics: Bool, completion: @escaping (TemporaryTwoStepPasswordToken) -> Void) -> AlertController {
|
||||
func botCheckoutPasswordEntryController(context: AccountContext, strings: PresentationStrings, passwordTip: String?, cartTitle: String, period: Int32, requiresBiometrics: Bool, completion: @escaping (TemporaryTwoStepPasswordToken) -> Void) -> AlertController {
|
||||
var dismissImpl: (() -> Void)?
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: BotCheckoutPasswordAlertContentNode(context: context, theme: presentationData.theme, strings: strings, cardTitle: cartTitle, period: period, requiresBiometrics: requiresBiometrics, cancel: {
|
||||
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: BotCheckoutPasswordAlertContentNode(context: context, theme: presentationData.theme, strings: strings, passwordTip: passwordTip, cardTitle: cartTitle, period: period, requiresBiometrics: requiresBiometrics, cancel: {
|
||||
dismissImpl?()
|
||||
}, completion: { token in
|
||||
completion(token)
|
||||
|
||||
@ -234,8 +234,7 @@ class BotCheckoutTipItemNode: ListViewItemNode, UITextFieldDelegate {
|
||||
|
||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: textFont, textColor: textColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - 20.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
//TODO:localize
|
||||
let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Enter Custom", font: textFont, textColor: textColor.withMultipliedAlpha(0.8)), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - 20.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.strings.Checkout_OptionalTipItemPlaceholder, font: textFont, textColor: textColor.withMultipliedAlpha(0.8)), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - 20.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
return (ListViewItemNodeLayout(contentSize: contentSize, insets: insets), { [weak self] in
|
||||
if let strongSelf = self {
|
||||
|
||||
@ -208,8 +208,7 @@ private func botReceiptControllerEntries(presentationData: PresentationData, inv
|
||||
}
|
||||
|
||||
if let tipAmount = tipAmount, tipAmount != 0 {
|
||||
//TODO:localize
|
||||
entries.append(.price(index, presentationData.theme, "Tip", formatCurrencyAmount(tipAmount, currency: formInvoice.currency), index == 0, false))
|
||||
entries.append(.price(index, presentationData.theme, presentationData.strings.Checkout_TipItem, formatCurrencyAmount(tipAmount, currency: formInvoice.currency), index == 0, false))
|
||||
totalPrice += tipAmount
|
||||
index += 1
|
||||
}
|
||||
|
||||
@ -144,12 +144,13 @@ private func cancelContextGestures(view: UIView) {
|
||||
}
|
||||
}
|
||||
|
||||
public final class PinchSourceContainerNode: ASDisplayNode {
|
||||
public final class PinchSourceContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
public let contentNode: ASDisplayNode
|
||||
public var contentRect: CGRect = CGRect()
|
||||
private(set) var naturalContentFrame: CGRect?
|
||||
|
||||
fileprivate let gesture: PinchSourceGesture
|
||||
fileprivate var panGesture: UIPanGestureRecognizer?
|
||||
|
||||
public var isPinchGestureEnabled: Bool = false {
|
||||
didSet {
|
||||
@ -217,6 +218,13 @@ public final class PinchSourceContainerNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func panGestureRecognized(_ recognizer: UIPanGestureRecognizer) {
|
||||
}
|
||||
|
||||
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
public func update(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
let contentFrame = CGRect(origin: CGPoint(), size: size)
|
||||
self.naturalContentFrame = contentFrame
|
||||
@ -290,10 +298,10 @@ private final class PinchControllerNode: ViewControllerTracingNode {
|
||||
)
|
||||
|
||||
var transform = CATransform3DIdentity
|
||||
transform = CATransform3DTranslate(transform, offset.x - pinchOffset.x * (scale - 1.0), offset.y - pinchOffset.y * (scale - 1.0), 0.0)
|
||||
transform = CATransform3DScale(transform, scale, scale, 0.0)
|
||||
|
||||
strongSelf.sourceNode.contentNode.transform = transform
|
||||
strongSelf.sourceNode.contentNode.position = CGPoint(x: initialSourceFrame.midX + offset.x - pinchOffset.x * (scale - 1.0), y: initialSourceFrame.midY + offset.y - pinchOffset.y * (scale - 1.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -32,8 +32,8 @@ public func largestRepresentationForPhoto(_ photo: TelegramMediaImage) -> Telegr
|
||||
|
||||
private let progressiveRangeMap: [(Int, [Int])] = [
|
||||
(100, [0]),
|
||||
(400, [1]),
|
||||
(600, [2, 3]),
|
||||
(400, [3]),
|
||||
(600, [4]),
|
||||
(Int(Int32.max), [2, 3, 4])
|
||||
]
|
||||
|
||||
|
||||
@ -173,7 +173,7 @@ extension BotPaymentRequestedInfo {
|
||||
}
|
||||
}
|
||||
|
||||
public func fetchBotPaymentForm(postbox: Postbox, network: Network, messageId: MessageId) -> Signal<BotPaymentForm, BotPaymentFormRequestError> {
|
||||
public func fetchBotPaymentForm(postbox: Postbox, network: Network, messageId: MessageId, themeParams: [String: Any]?) -> Signal<BotPaymentForm, BotPaymentFormRequestError> {
|
||||
return postbox.transaction { transaction -> Api.InputPeer? in
|
||||
return transaction.getPeer(messageId.peerId).flatMap(apiInputPeer)
|
||||
}
|
||||
@ -182,7 +182,16 @@ public func fetchBotPaymentForm(postbox: Postbox, network: Network, messageId: M
|
||||
guard let inputPeer = inputPeer else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
return network.request(Api.functions.payments.getPaymentForm(flags: 0, peer: inputPeer, msgId: messageId.id, themeParams: nil))
|
||||
var flags: Int32 = 0
|
||||
var serializedThemeParams: Api.DataJSON?
|
||||
if let themeParams = themeParams, let data = try? JSONSerialization.data(withJSONObject: themeParams, options: []), let dataString = String(data: data, encoding: .utf8) {
|
||||
serializedThemeParams = Api.DataJSON.dataJSON(data: dataString)
|
||||
}
|
||||
if serializedThemeParams != nil {
|
||||
flags |= 1 << 0
|
||||
}
|
||||
|
||||
return network.request(Api.functions.payments.getPaymentForm(flags: flags, peer: inputPeer, msgId: messageId.id, themeParams: serializedThemeParams))
|
||||
|> `catch` { _ -> Signal<Api.payments.PaymentForm, BotPaymentFormRequestError> in
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user