Merge branches 'master' and 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2021-04-09 18:26:44 +03:00
commit 045d102294
10 changed files with 4546 additions and 4495 deletions

View File

@ -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";

View File

@ -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)

View File

@ -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)

View File

@ -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 {

View File

@ -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
}

View File

@ -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))
}
}

View File

@ -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])
]

View File

@ -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)
}