mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes
This commit is contained in:
parent
b4e057f444
commit
e15dca9bcc
@ -7962,6 +7962,7 @@ Sorry for the inconvenience.";
|
||||
"Emoji.FrequentlyUsed" = "Recently Used";
|
||||
|
||||
"Premium.Annual" = "Annual";
|
||||
"Premium.Semiannual" = "Semiannual";
|
||||
"Premium.Monthly" = "Monthly";
|
||||
|
||||
"Login.PhoneNumberConfirmation" = "Is this the correct number?";
|
||||
|
@ -11,6 +11,8 @@ public final class AuthorizationSequenceCodeEntryController: ViewController {
|
||||
return self.displayNode as! AuthorizationSequenceCodeEntryControllerNode
|
||||
}
|
||||
|
||||
private var validLayout: ContainerViewLayout?
|
||||
|
||||
private let strings: PresentationStrings
|
||||
private let theme: PresentationTheme
|
||||
private let openUrl: (String) -> Void
|
||||
@ -30,12 +32,7 @@ public final class AuthorizationSequenceCodeEntryController: ViewController {
|
||||
|
||||
public var inProgress: Bool = false {
|
||||
didSet {
|
||||
// if self.inProgress {
|
||||
// let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: self.theme.rootController.navigationBar.accentTextColor))
|
||||
// self.navigationItem.rightBarButtonItem = item
|
||||
// } else {
|
||||
// self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed))
|
||||
// }
|
||||
self.updateNavigationItems()
|
||||
self.controllerNode.inProgress = self.inProgress
|
||||
}
|
||||
}
|
||||
@ -52,9 +49,7 @@ public final class AuthorizationSequenceCodeEntryController: ViewController {
|
||||
self.hasActiveInput = true
|
||||
|
||||
self.statusBar.statusBarStyle = theme.intro.statusBarStyle.style
|
||||
|
||||
// self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed))
|
||||
|
||||
|
||||
self.attemptNavigation = { _ in
|
||||
return false
|
||||
}
|
||||
@ -124,6 +119,19 @@ public final class AuthorizationSequenceCodeEntryController: ViewController {
|
||||
self.controllerNode.animateError(text: text)
|
||||
}
|
||||
|
||||
func updateNavigationItems() {
|
||||
guard let layout = self.validLayout, layout.size.width < 360.0 else {
|
||||
return
|
||||
}
|
||||
|
||||
if self.inProgress {
|
||||
let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: self.theme.rootController.navigationBar.accentTextColor))
|
||||
self.navigationItem.rightBarButtonItem = item
|
||||
} else {
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed))
|
||||
}
|
||||
}
|
||||
|
||||
public func updateData(number: String, email: String?, codeType: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, timeout: Int32?, termsOfService: (UnauthorizedAccountTermsOfService, Bool)?) {
|
||||
self.termsOfService = termsOfService
|
||||
if self.data?.0 != number || self.data?.1 != email || self.data?.2 != codeType || self.data?.3 != nextType || self.data?.4 != timeout {
|
||||
@ -144,6 +152,13 @@ public final class AuthorizationSequenceCodeEntryController: ViewController {
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
let hadLayout = self.validLayout != nil
|
||||
self.validLayout = layout
|
||||
|
||||
if !hadLayout {
|
||||
self.updateNavigationItems()
|
||||
}
|
||||
|
||||
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
|
||||
}
|
||||
|
||||
|
@ -249,7 +249,9 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
controller.present(strongSelf.sharedContext.makeProxySettingsController(sharedContext: strongSelf.sharedContext, account: strongSelf.account), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}))
|
||||
}
|
||||
controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: text, actions: actions), in: .window(.root))
|
||||
(controller.navigationController as? NavigationController)?.presentOverlay(controller: standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: text, actions: actions), inGlobal: true, blockInteraction: true)
|
||||
|
||||
controller.dismissConfirmation()
|
||||
}
|
||||
}))
|
||||
}
|
||||
@ -645,7 +647,6 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
// lastController?.inProgress = false
|
||||
switch result {
|
||||
case let .signUp(data):
|
||||
let _ = beginSignUp(account: strongSelf.account, data: data).start()
|
||||
@ -655,8 +656,6 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
}, error: { [weak self, weak lastController] error in
|
||||
Queue.mainQueue().async {
|
||||
if let strongSelf = self, let lastController = lastController {
|
||||
// controller.inProgress = false
|
||||
|
||||
let text: String
|
||||
switch error {
|
||||
case .limitExceeded:
|
||||
|
@ -17,6 +17,8 @@ public final class AuthorizationSequenceEmailEntryController: ViewController {
|
||||
return self.displayNode as! AuthorizationSequenceEmailEntryControllerNode
|
||||
}
|
||||
|
||||
private var validLayout: ContainerViewLayout?
|
||||
|
||||
private let presentationData: PresentationData
|
||||
|
||||
public var proceedWithEmail: ((String) -> Void)?
|
||||
@ -28,12 +30,7 @@ public final class AuthorizationSequenceEmailEntryController: ViewController {
|
||||
|
||||
public var inProgress: Bool = false {
|
||||
didSet {
|
||||
// if self.inProgress {
|
||||
// let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: self.presentationData.theme.rootController.navigationBar.accentTextColor))
|
||||
// self.navigationItem.rightBarButtonItem = item
|
||||
// } else {
|
||||
// self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed))
|
||||
// }
|
||||
self.updateNavigationItems()
|
||||
self.controllerNode.inProgress = self.inProgress
|
||||
}
|
||||
}
|
||||
@ -56,8 +53,6 @@ public final class AuthorizationSequenceEmailEntryController: ViewController {
|
||||
self.navigationBar?.backPressed = {
|
||||
back()
|
||||
}
|
||||
|
||||
// self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed))
|
||||
}
|
||||
|
||||
required init(coder aDecoder: NSCoder) {
|
||||
@ -87,6 +82,19 @@ public final class AuthorizationSequenceEmailEntryController: ViewController {
|
||||
self.controllerNode.activateInput()
|
||||
}
|
||||
|
||||
func updateNavigationItems() {
|
||||
guard let layout = self.validLayout, layout.size.width < 360.0 else {
|
||||
return
|
||||
}
|
||||
|
||||
if self.inProgress {
|
||||
let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: self.presentationData.theme.rootController.navigationBar.accentTextColor))
|
||||
self.navigationItem.rightBarButtonItem = item
|
||||
} else {
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed))
|
||||
}
|
||||
}
|
||||
|
||||
public func updateData(appleSignInAllowed: Bool) {
|
||||
var appleSignInAllowed = appleSignInAllowed
|
||||
if #available(iOS 13.0, *) {
|
||||
@ -104,6 +112,13 @@ public final class AuthorizationSequenceEmailEntryController: ViewController {
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
let hadLayout = self.validLayout != nil
|
||||
self.validLayout = layout
|
||||
|
||||
if !hadLayout {
|
||||
self.updateNavigationItems()
|
||||
}
|
||||
|
||||
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,6 @@ final class AuthorizationSequenceEmailEntryControllerNode: ASDisplayNode, UIText
|
||||
|
||||
self.animationNode = DefaultAnimatedStickerNodeImpl()
|
||||
self.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "IntroMail"), width: 256, height: 256, playbackMode: .once, mode: .direct(cachePathPrefix: nil))
|
||||
self.animationNode.visibility = true
|
||||
|
||||
self.titleNode = ASTextNode()
|
||||
self.titleNode.isUserInteractionEnabled = false
|
||||
@ -189,11 +188,12 @@ final class AuthorizationSequenceEmailEntryControllerNode: ASDisplayNode, UIText
|
||||
|
||||
var insets = layout.insets(options: [])
|
||||
insets.top = layout.statusBarHeight ?? 20.0
|
||||
|
||||
if let inputHeight = layout.inputHeight {
|
||||
insets.bottom = max(inputHeight, insets.bottom)
|
||||
}
|
||||
|
||||
let titleInset: CGFloat = layout.size.width > 320.0 ? 18.0 : 0.0
|
||||
|
||||
self.titleNode.attributedText = NSAttributedString(string: self.mode == .setup ? self.strings.Login_AddEmailTitle : self.strings.Login_EnterNewEmailTitle, font: Font.bold(28.0), textColor: self.theme.list.itemPrimaryTextColor)
|
||||
|
||||
let animationSize = CGSize(width: 100.0, height: 100.0)
|
||||
@ -204,15 +204,25 @@ final class AuthorizationSequenceEmailEntryControllerNode: ASDisplayNode, UIText
|
||||
let proceedSize = CGSize(width: layout.size.width - 48.0, height: proceedHeight)
|
||||
|
||||
var items: [AuthorizationLayoutItem] = []
|
||||
items.append(AuthorizationLayoutItem(node: self.animationNode, size: animationSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 10.0, maxValue: 10.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
|
||||
self.animationNode.updateLayout(size: animationSize)
|
||||
|
||||
items.append(AuthorizationLayoutItem(node: self.titleNode, size: titleSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 18.0, maxValue: 18.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
|
||||
items.append(AuthorizationLayoutItem(node: self.titleNode, size: titleSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: titleInset, maxValue: titleInset), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
|
||||
items.append(AuthorizationLayoutItem(node: self.noticeNode, size: noticeSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 18.0, maxValue: 18.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
|
||||
|
||||
items.append(AuthorizationLayoutItem(node: self.codeField, size: CGSize(width: layout.size.width - 88.0, height: 44.0), spacingBefore: AuthorizationLayoutItemSpacing(weight: 22.0, maxValue: 40.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
|
||||
items.append(AuthorizationLayoutItem(node: self.codeSeparatorNode, size: CGSize(width: layout.size.width - 48.0, height: UIScreenPixel), spacingBefore: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
|
||||
|
||||
if layout.size.width > 320.0 {
|
||||
items.insert(AuthorizationLayoutItem(node: self.animationNode, size: animationSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 10.0, maxValue: 10.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)), at: 0)
|
||||
self.animationNode.updateLayout(size: animationSize)
|
||||
self.proceedNode.isHidden = false
|
||||
self.animationNode.isHidden = false
|
||||
self.animationNode.visibility = true
|
||||
} else {
|
||||
insets.top = navigationBarHeight
|
||||
self.proceedNode.isHidden = true
|
||||
self.animationNode.isHidden = true
|
||||
}
|
||||
|
||||
let inset: CGFloat = 24.0
|
||||
let buttonFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - proceedSize.width) / 2.0), y: layout.size.height - insets.bottom - proceedSize.height - inset), size: proceedSize)
|
||||
transition.updateFrame(node: self.proceedNode, frame: buttonFrame)
|
||||
|
@ -17,6 +17,8 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
|
||||
return self.displayNode as! AuthorizationSequencePhoneEntryControllerNode
|
||||
}
|
||||
|
||||
private var validLayout: ContainerViewLayout?
|
||||
|
||||
private let sharedContext: SharedAccountContext
|
||||
private var account: UnauthorizedAccount
|
||||
private let isTestingEnvironment: Bool
|
||||
@ -43,12 +45,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
|
||||
|
||||
var inProgress: Bool = false {
|
||||
didSet {
|
||||
// if self.inProgress {
|
||||
// let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: self.presentationData.theme.rootController.navigationBar.accentTextColor))
|
||||
// self.navigationItem.rightBarButtonItem = item
|
||||
// } else {
|
||||
// self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed))
|
||||
// }
|
||||
self.updateNavigationItems()
|
||||
self.controllerNode.inProgress = self.inProgress
|
||||
self.confirmationController?.inProgress = self.inProgress
|
||||
}
|
||||
@ -89,7 +86,6 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
|
||||
if !otherAccountPhoneNumbers.1.isEmpty {
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
|
||||
}
|
||||
// self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed))
|
||||
}
|
||||
|
||||
required init(coder aDecoder: NSCoder) {
|
||||
@ -104,6 +100,19 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
|
||||
self.back()
|
||||
}
|
||||
|
||||
func updateNavigationItems() {
|
||||
guard let layout = self.validLayout, layout.size.width < 360.0 else {
|
||||
return
|
||||
}
|
||||
|
||||
if self.inProgress {
|
||||
let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: self.presentationData.theme.rootController.navigationBar.accentTextColor))
|
||||
self.navigationItem.rightBarButtonItem = item
|
||||
} else {
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed))
|
||||
}
|
||||
}
|
||||
|
||||
func updateData(countryCode: Int32, countryName: String?, number: String) {
|
||||
self.currentData = (countryCode, countryName, number)
|
||||
if self.isNodeLoaded {
|
||||
@ -207,6 +216,13 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
|
||||
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
let hadLayout = self.validLayout != nil
|
||||
self.validLayout = layout
|
||||
|
||||
if !hadLayout {
|
||||
self.updateNavigationItems()
|
||||
}
|
||||
|
||||
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
|
||||
|
||||
if self.shouldAnimateIn, let inputHeight = layout.inputHeight, inputHeight > 0.0 {
|
||||
@ -217,6 +233,11 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
func dismissConfirmation() {
|
||||
self.confirmationController?.dismissAnimated()
|
||||
self.confirmationController = nil
|
||||
}
|
||||
|
||||
@objc func nextPressed() {
|
||||
let (_, _, number) = self.controllerNode.codeAndNumber
|
||||
if !number.isEmpty {
|
||||
@ -239,16 +260,27 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
|
||||
actions.append(TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {}))
|
||||
self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Login_PhoneNumberAlreadyAuthorized, actions: actions), in: .window(.root))
|
||||
} else {
|
||||
let (code, formattedNumber) = self.controllerNode.formattedCodeAndNumber
|
||||
if let validLayout = self.validLayout, validLayout.size.width > 320.0 {
|
||||
let (code, formattedNumber) = self.controllerNode.formattedCodeAndNumber
|
||||
|
||||
let confirmationController = PhoneConfirmationController(theme: self.presentationData.theme, strings: self.presentationData.strings, code: code, number: formattedNumber, sourceController: self)
|
||||
confirmationController.proceed = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.loginWithNumber?(strongSelf.controllerNode.currentNumber, strongSelf.controllerNode.syncContacts)
|
||||
let confirmationController = PhoneConfirmationController(theme: self.presentationData.theme, strings: self.presentationData.strings, code: code, number: formattedNumber, sourceController: self)
|
||||
confirmationController.proceed = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.loginWithNumber?(strongSelf.controllerNode.currentNumber, strongSelf.controllerNode.syncContacts)
|
||||
}
|
||||
}
|
||||
(self.navigationController as? NavigationController)?.presentOverlay(controller: confirmationController, inGlobal: true, blockInteraction: true)
|
||||
self.confirmationController = confirmationController
|
||||
} else {
|
||||
var actions: [TextAlertAction] = []
|
||||
actions.append(TextAlertAction(type: .genericAction, title: self.presentationData.strings.Login_Edit, action: {}))
|
||||
actions.append(TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Login_Yes, action: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.loginWithNumber?(strongSelf.controllerNode.currentNumber, strongSelf.controllerNode.syncContacts)
|
||||
}
|
||||
}))
|
||||
self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: logInNumber, text: self.presentationData.strings.Login_PhoneNumberConfirmation, actions: actions), in: .window(.root))
|
||||
}
|
||||
(self.navigationController as? NavigationController)?.presentOverlay(controller: confirmationController, inGlobal: true, blockInteraction: true)
|
||||
self.confirmationController = confirmationController
|
||||
}
|
||||
} else {
|
||||
self.hapticFeedback.error()
|
||||
|
@ -227,7 +227,7 @@ private final class PhoneAndCountryNode: ASDisplayNode {
|
||||
self.phoneBackground.frame = CGRect(origin: CGPoint(x: 0.0, y: size.height - 57.0), size: CGSize(width: size.width - inset, height: 57.0))
|
||||
|
||||
let countryCodeFrame = CGRect(origin: CGPoint(x: 18.0, y: size.height - 58.0), size: CGSize(width: 71.0, height: 57.0))
|
||||
let numberFrame = CGRect(origin: CGPoint(x: 107.0, y: size.height - 58.0), size: CGSize(width: size.width - 96.0 - 8.0, height: 57.0))
|
||||
let numberFrame = CGRect(origin: CGPoint(x: 107.0, y: size.height - 58.0), size: CGSize(width: size.width - 96.0 - 8.0 - 24.0, height: 57.0))
|
||||
let placeholderFrame = numberFrame.offsetBy(dx: 0.0, dy: 17.0 - UIScreenPixel)
|
||||
|
||||
let phoneInputFrame = countryCodeFrame.union(numberFrame)
|
||||
@ -360,7 +360,6 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
|
||||
|
||||
self.animationNode = DefaultAnimatedStickerNodeImpl()
|
||||
self.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "IntroPhone"), width: 256, height: 256, playbackMode: .once, mode: .direct(cachePathPrefix: nil))
|
||||
self.animationNode.visibility = true
|
||||
|
||||
self.managedAnimationNode = ManagedPhoneAnimationNode()
|
||||
self.managedAnimationNode.isHidden = true
|
||||
@ -479,9 +478,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
|
||||
|
||||
func animateIn(buttonFrame: CGRect, buttonTitle: String, animationSnapshot: UIView, textSnapshot: UIView) {
|
||||
self.proceedNode.animateTitle(to: self.strings.Login_Continue)
|
||||
|
||||
let duration: Double = 0.3
|
||||
|
||||
|
||||
self.animationSnapshotView?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak self] _ in
|
||||
self?.animationSnapshotView?.removeFromSuperview()
|
||||
self?.animationSnapshotView = nil
|
||||
@ -507,7 +504,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
|
||||
|
||||
for node in nodes {
|
||||
node.alpha = 1.0
|
||||
node.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||
node.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
}
|
||||
}
|
||||
|
||||
@ -518,11 +515,13 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
var insets = layout.insets(options: [])
|
||||
insets.top = layout.statusBarHeight ?? 20.0
|
||||
|
||||
if let inputHeight = layout.inputHeight, !inputHeight.isZero {
|
||||
insets.bottom = max(inputHeight, insets.bottom)
|
||||
}
|
||||
|
||||
let titleInset: CGFloat = layout.size.width > 320.0 ? 18.0 : 0.0
|
||||
let additionalBottomInset: CGFloat = layout.size.width > 320.0 ? 80.0 : 10.0
|
||||
|
||||
self.titleNode.attributedText = NSAttributedString(string: strings.Login_PhoneTitle, font: Font.bold(28.0), textColor: self.theme.list.itemPrimaryTextColor)
|
||||
|
||||
let inset: CGFloat = 24.0
|
||||
@ -534,11 +533,23 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
|
||||
let proceedSize = CGSize(width: layout.size.width - inset * 2.0, height: proceedHeight)
|
||||
|
||||
var items: [AuthorizationLayoutItem] = [
|
||||
AuthorizationLayoutItem(node: self.animationNode, size: animationSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 10.0, maxValue: 10.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)),
|
||||
AuthorizationLayoutItem(node: self.titleNode, size: titleSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 18.0, maxValue: 18.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)),
|
||||
AuthorizationLayoutItem(node: self.titleNode, size: titleSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: titleInset, maxValue: titleInset), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)),
|
||||
AuthorizationLayoutItem(node: self.noticeNode, size: noticeSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 18.0, maxValue: 18.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)),
|
||||
AuthorizationLayoutItem(node: self.phoneAndCountryNode, size: CGSize(width: layout.size.width, height: 115.0), spacingBefore: AuthorizationLayoutItemSpacing(weight: 30.0, maxValue: 30.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)),
|
||||
]
|
||||
|
||||
if layout.size.width > 320.0 {
|
||||
items.insert(AuthorizationLayoutItem(node: self.animationNode, size: animationSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 10.0, maxValue: 10.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)), at: 0)
|
||||
self.proceedNode.isHidden = false
|
||||
self.animationNode.isHidden = false
|
||||
self.animationNode.visibility = true
|
||||
} else {
|
||||
insets.top = navigationBarHeight
|
||||
self.proceedNode.isHidden = true
|
||||
self.animationNode.isHidden = true
|
||||
self.managedAnimationNode.isHidden = true
|
||||
}
|
||||
|
||||
let contactSyncSize = self.contactSyncNode.updateLayout(width: layout.size.width)
|
||||
if self.hasOtherAccounts {
|
||||
self.contactSyncNode.isHidden = false
|
||||
@ -558,7 +569,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
|
||||
|
||||
self.animationNode.updateLayout(size: animationSize)
|
||||
|
||||
let _ = layoutAuthorizationItems(bounds: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: layout.size.height - insets.top - insets.bottom - 80.0)), items: items, transition: transition, failIfDoesNotFit: false)
|
||||
let _ = layoutAuthorizationItems(bounds: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: layout.size.height - insets.top - insets.bottom - additionalBottomInset)), items: items, transition: transition, failIfDoesNotFit: false)
|
||||
|
||||
transition.updateFrame(node: self.managedAnimationNode, frame: self.animationNode.frame)
|
||||
}
|
||||
@ -696,7 +707,12 @@ final class PhoneConfirmationController: ViewController {
|
||||
|
||||
var proceed: () -> Void = {}
|
||||
|
||||
class Node: ASDisplayNode {
|
||||
class Node: ASDisplayNode {
|
||||
private let theme: PresentationTheme
|
||||
|
||||
private let code: String
|
||||
private let number: String
|
||||
|
||||
private let dimNode: ASDisplayNode
|
||||
private let backgroundNode: ASDisplayNode
|
||||
|
||||
@ -714,7 +730,14 @@ final class PhoneConfirmationController: ViewController {
|
||||
var proceed: () -> Void = {}
|
||||
var cancel: () -> Void = {}
|
||||
|
||||
private var validLayout: ContainerViewLayout?
|
||||
|
||||
init(theme: PresentationTheme, strings: PresentationStrings, code: String, number: String) {
|
||||
self.theme = theme
|
||||
|
||||
self.code = code
|
||||
self.number = number
|
||||
|
||||
self.dimNode = ASDisplayNode()
|
||||
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.4)
|
||||
|
||||
@ -753,7 +776,6 @@ final class PhoneConfirmationController: ViewController {
|
||||
self.codeTargetNode.displaysAsynchronously = false
|
||||
self.codeTargetNode.attributedText = NSAttributedString(string: code, font: largeFont, textColor: theme.list.itemPrimaryTextColor)
|
||||
|
||||
|
||||
self.phoneTargetNode = ImmediateTextNode()
|
||||
self.phoneTargetNode.displaysAsynchronously = false
|
||||
|
||||
@ -801,6 +823,9 @@ final class PhoneConfirmationController: ViewController {
|
||||
}
|
||||
|
||||
func animateIn(codeNode: ASDisplayNode, numberNode: ASDisplayNode, buttonNode: ASDisplayNode) {
|
||||
guard let layout = self.validLayout else {
|
||||
return
|
||||
}
|
||||
let codeFrame = codeNode.convert(codeNode.bounds, to: nil)
|
||||
let numberFrame = numberNode.convert(numberNode.bounds, to: nil)
|
||||
let buttonFrame = buttonNode.convert(buttonNode.bounds, to: nil)
|
||||
@ -811,43 +836,45 @@ final class PhoneConfirmationController: ViewController {
|
||||
|
||||
self.dimNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
|
||||
let codeSize = self.codeSourceNode.updateLayout(self.frame.size)
|
||||
let duration: Double = 0.25
|
||||
|
||||
let codeSize = self.codeSourceNode.updateLayout(layout.size)
|
||||
self.codeSourceNode.frame = CGRect(origin: CGPoint(x: codeFrame.midX - codeSize.width / 2.0, y: codeFrame.midY - codeSize.height / 2.0), size: codeSize)
|
||||
|
||||
let numberSize = self.phoneSourceNode.updateLayout(self.frame.size)
|
||||
let numberSize = self.phoneSourceNode.updateLayout(layout.size)
|
||||
self.phoneSourceNode.frame = CGRect(origin: CGPoint(x: numberFrame.minX, y: numberFrame.midY - numberSize.height / 2.0), size: numberSize)
|
||||
|
||||
let targetScale = codeSize.height / self.codeTargetNode.frame.height
|
||||
let sourceScale = self.codeTargetNode.frame.height / codeSize.height
|
||||
|
||||
self.codeSourceNode.layer.animateScale(from: 1.0, to: sourceScale, duration: 0.3)
|
||||
self.codeSourceNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
|
||||
self.codeSourceNode.layer.animatePosition(from: self.codeSourceNode.position, to: self.codeTargetNode.position, duration: 0.3)
|
||||
self.codeSourceNode.layer.animateScale(from: 1.0, to: sourceScale, duration: duration)
|
||||
self.codeSourceNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
|
||||
self.codeSourceNode.layer.animatePosition(from: self.codeSourceNode.position, to: self.codeTargetNode.position, duration: duration)
|
||||
|
||||
self.phoneSourceNode.layer.animateScale(from: 1.0, to: sourceScale, duration: 0.3)
|
||||
self.phoneSourceNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
|
||||
self.phoneSourceNode.layer.animatePosition(from: self.phoneSourceNode.position, to: self.phoneTargetNode.position, duration: 0.3)
|
||||
self.phoneSourceNode.layer.animateScale(from: 1.0, to: sourceScale, duration: duration)
|
||||
self.phoneSourceNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration)
|
||||
self.phoneSourceNode.layer.animatePosition(from: self.phoneSourceNode.position, to: self.phoneTargetNode.position, duration: duration)
|
||||
|
||||
self.codeTargetNode.layer.animateScale(from: targetScale, to: 1.0, duration: 0.3)
|
||||
self.codeTargetNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
self.codeTargetNode.layer.animatePosition(from: self.codeSourceNode.position, to: self.codeTargetNode.position, duration: 0.3)
|
||||
self.codeTargetNode.layer.animateScale(from: targetScale, to: 1.0, duration: duration)
|
||||
self.codeTargetNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||
self.codeTargetNode.layer.animatePosition(from: self.codeSourceNode.position, to: self.codeTargetNode.position, duration: duration)
|
||||
|
||||
self.phoneTargetNode.layer.animateScale(from: targetScale, to: 1.0, duration: 0.3)
|
||||
self.phoneTargetNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
self.phoneTargetNode.layer.animatePosition(from: self.phoneSourceNode.position, to: self.phoneTargetNode.position, duration: 0.3)
|
||||
self.phoneTargetNode.layer.animateScale(from: targetScale, to: 1.0, duration: duration)
|
||||
self.phoneTargetNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||
self.phoneTargetNode.layer.animatePosition(from: self.phoneSourceNode.position, to: self.phoneTargetNode.position, duration: duration)
|
||||
|
||||
self.backgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
||||
self.backgroundNode.layer.animateFrame(from: CGRect(origin: CGPoint(x: 14.0, y: codeFrame.minY), size: CGSize(width: self.backgroundNode.frame.width - 12.0, height: buttonFrame.maxY + 18.0 - codeFrame.minY)), to: self.backgroundNode.frame, duration: 0.3)
|
||||
self.backgroundNode.layer.animateFrame(from: CGRect(origin: CGPoint(x: 14.0, y: codeFrame.minY), size: CGSize(width: self.backgroundNode.frame.width - 12.0, height: buttonFrame.maxY + 18.0 - codeFrame.minY)), to: self.backgroundNode.frame, duration: duration)
|
||||
|
||||
self.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
self.textNode.layer.animateScale(from: 0.5, to: 1.0, duration: 0.3)
|
||||
self.textNode.layer.animatePosition(from: CGPoint(x: -100.0, y: -45.0), to: CGPoint(), duration: 0.3, additive: true)
|
||||
self.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||
self.textNode.layer.animateScale(from: 0.5, to: 1.0, duration: duration)
|
||||
self.textNode.layer.animatePosition(from: CGPoint(x: -100.0, y: -45.0), to: CGPoint(), duration: duration, additive: true)
|
||||
|
||||
self.cancelButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
self.cancelButton.layer.animateScale(from: 0.5, to: 1.0, duration: 0.3)
|
||||
self.cancelButton.layer.animatePosition(from: CGPoint(x: -100.0, y: -70.0), to: CGPoint(), duration: 0.3, additive: true)
|
||||
self.cancelButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||
self.cancelButton.layer.animateScale(from: 0.5, to: 1.0, duration: duration)
|
||||
self.cancelButton.layer.animatePosition(from: CGPoint(x: -100.0, y: -70.0), to: CGPoint(), duration: duration, additive: true)
|
||||
|
||||
self.proceedNode.layer.animatePosition(from: buttonFrame.center, to: self.proceedNode.position, duration: 0.3)
|
||||
self.proceedNode.layer.animatePosition(from: buttonFrame.center, to: self.proceedNode.position, duration: duration)
|
||||
}
|
||||
|
||||
func animateOut(codeNode: ASDisplayNode, numberNode: ASDisplayNode, buttonNode: ASDisplayNode, completion: @escaping () -> Void) {
|
||||
@ -857,6 +884,8 @@ final class PhoneConfirmationController: ViewController {
|
||||
|
||||
self.dimNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
|
||||
let duration: Double = 0.25
|
||||
|
||||
let codeSize = self.codeSourceNode.updateLayout(self.frame.size)
|
||||
self.codeSourceNode.frame = CGRect(origin: CGPoint(x: codeFrame.midX - codeSize.width / 2.0, y: codeFrame.midY - codeSize.height / 2.0), size: codeSize)
|
||||
|
||||
@ -866,45 +895,48 @@ final class PhoneConfirmationController: ViewController {
|
||||
let targetScale = codeSize.height / self.codeTargetNode.frame.height
|
||||
let sourceScale = self.codeTargetNode.frame.height / codeSize.height
|
||||
|
||||
self.codeSourceNode.layer.animateScale(from: sourceScale, to: 1.0, duration: 0.3)
|
||||
self.codeSourceNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
self.codeSourceNode.layer.animatePosition(from: self.codeTargetNode.position, to: self.codeSourceNode.position, duration: 0.3)
|
||||
self.codeSourceNode.layer.animateScale(from: sourceScale, to: 1.0, duration: duration)
|
||||
self.codeSourceNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||
self.codeSourceNode.layer.animatePosition(from: self.codeTargetNode.position, to: self.codeSourceNode.position, duration: duration)
|
||||
|
||||
self.phoneSourceNode.layer.animateScale(from: sourceScale, to: 1.0, duration: 0.3)
|
||||
self.phoneSourceNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
self.phoneSourceNode.layer.animatePosition(from: self.phoneTargetNode.position, to: self.phoneSourceNode.position, duration: 0.3)
|
||||
self.phoneSourceNode.layer.animateScale(from: sourceScale, to: 1.0, duration: duration)
|
||||
self.phoneSourceNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||
self.phoneSourceNode.layer.animatePosition(from: self.phoneTargetNode.position, to: self.phoneSourceNode.position, duration: duration)
|
||||
|
||||
self.codeTargetNode.layer.animateScale(from: 1.0, to: targetScale, duration: 0.3)
|
||||
self.codeTargetNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
|
||||
self.codeTargetNode.layer.animatePosition(from: self.codeTargetNode.position, to: self.codeSourceNode.position, duration: 0.3)
|
||||
self.codeTargetNode.layer.animateScale(from: 1.0, to: targetScale, duration: duration)
|
||||
self.codeTargetNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration, removeOnCompletion: false)
|
||||
self.codeTargetNode.layer.animatePosition(from: self.codeTargetNode.position, to: self.codeSourceNode.position, duration: duration)
|
||||
|
||||
Queue.mainQueue().after(0.25) {
|
||||
Queue.mainQueue().after(0.23) {
|
||||
codeNode.isHidden = false
|
||||
numberNode.isHidden = false
|
||||
buttonNode.isHidden = false
|
||||
}
|
||||
|
||||
self.phoneTargetNode.layer.animateScale(from: 1.0, to: targetScale, duration: 0.3)
|
||||
self.phoneTargetNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in
|
||||
self.phoneTargetNode.layer.animateScale(from: 1.0, to: targetScale, duration: duration)
|
||||
self.phoneTargetNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration, removeOnCompletion: false, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
self.phoneTargetNode.layer.animatePosition(from: self.phoneTargetNode.position, to: self.phoneSourceNode.position, duration: 0.3)
|
||||
self.phoneTargetNode.layer.animatePosition(from: self.phoneTargetNode.position, to: self.phoneSourceNode.position, duration: duration)
|
||||
|
||||
self.backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, delay: 0.1, removeOnCompletion: false)
|
||||
self.backgroundNode.layer.animateFrame(from: self.backgroundNode.frame, to: CGRect(origin: CGPoint(x: 14.0, y: codeFrame.minY), size: CGSize(width: self.backgroundNode.frame.width - 12.0, height: buttonFrame.maxY + 18.0 - codeFrame.minY)), duration: 0.3)
|
||||
self.backgroundNode.layer.animateFrame(from: self.backgroundNode.frame, to: CGRect(origin: CGPoint(x: 14.0, y: codeFrame.minY), size: CGSize(width: self.backgroundNode.frame.width - 12.0, height: buttonFrame.maxY + 18.0 - codeFrame.minY)), duration: duration)
|
||||
|
||||
self.textNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
self.textNode.layer.animateScale(from: 1.0, to: 0.5, duration: 0.3, removeOnCompletion: false)
|
||||
self.textNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: -100.0, y: -45.0), duration: 0.3, removeOnCompletion: false, additive: true)
|
||||
self.textNode.layer.animateScale(from: 1.0, to: 0.5, duration: duration, removeOnCompletion: false)
|
||||
self.textNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: -100.0, y: -45.0), duration: duration, removeOnCompletion: false, additive: true)
|
||||
|
||||
self.cancelButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
self.cancelButton.layer.animateScale(from: 1.0, to: 0.5, duration: 0.3, removeOnCompletion: false)
|
||||
self.cancelButton.layer.animatePosition(from: CGPoint(), to: CGPoint(x: -100.0, y: -70.0), duration: 0.3, removeOnCompletion: false, additive: true)
|
||||
self.cancelButton.layer.animateScale(from: 1.0, to: 0.5, duration: duration, removeOnCompletion: false)
|
||||
self.cancelButton.layer.animatePosition(from: CGPoint(), to: CGPoint(x: -100.0, y: -70.0), duration: duration, removeOnCompletion: false, additive: true)
|
||||
|
||||
self.proceedNode.layer.animatePosition(from: self.proceedNode.position, to: buttonFrame.center, duration: 0.3, removeOnCompletion: false)
|
||||
self.proceedNode.layer.animatePosition(from: self.proceedNode.position, to: buttonFrame.center, duration: duration, removeOnCompletion: false)
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
let hadLayout = self.validLayout != nil
|
||||
self.validLayout = layout
|
||||
|
||||
let sideInset: CGFloat = 8.0
|
||||
let innerInset: CGFloat = 18.0
|
||||
|
||||
@ -913,16 +945,33 @@ final class PhoneConfirmationController: ViewController {
|
||||
let backgroundSize = CGSize(width: layout.size.width - sideInset * 2.0, height: 243.0)
|
||||
let backgroundFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - backgroundSize.width) / 2.0), y: layout.size.height - backgroundSize.height - 260.0), size: backgroundSize)
|
||||
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
|
||||
|
||||
let maxWidth = layout.size.width - 20.0
|
||||
if !hadLayout {
|
||||
var fontSize = 34.0
|
||||
if layout.size.width < 375.0 {
|
||||
fontSize = 30.0
|
||||
}
|
||||
|
||||
let largeFont = Font.with(size: fontSize, design: .regular, weight: .bold, traits: [.monospacedNumbers])
|
||||
|
||||
self.codeTargetNode.attributedText = NSAttributedString(string: self.code, font: largeFont, textColor: self.theme.list.itemPrimaryTextColor)
|
||||
let targetString = NSMutableAttributedString(string: self.number, font: largeFont, textColor: self.theme.list.itemPrimaryTextColor)
|
||||
targetString.addAttribute(NSAttributedString.Key.kern, value: 1.6, range: NSRange(location: 0, length: targetString.length))
|
||||
self.phoneTargetNode.attributedText = targetString
|
||||
}
|
||||
|
||||
let codeSize = self.codeTargetNode.updateLayout(backgroundSize)
|
||||
let numberSize = self.phoneTargetNode.updateLayout(backgroundSize)
|
||||
let spacing: CGFloat = 10.0
|
||||
|
||||
let totalWidth = codeSize.width + numberSize.width + 10.0
|
||||
let codeSize = self.codeTargetNode.updateLayout(CGSize(width: maxWidth, height: .greatestFiniteMagnitude))
|
||||
let numberSize = self.phoneTargetNode.updateLayout(CGSize(width: maxWidth - codeSize.width - spacing, height: .greatestFiniteMagnitude))
|
||||
|
||||
let totalWidth = codeSize.width + numberSize.width + spacing
|
||||
|
||||
let codeFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - totalWidth) / 2.0), y: 30.0), size: codeSize)
|
||||
transition.updateFrame(node: self.codeTargetNode, frame: codeFrame.offsetBy(dx: backgroundFrame.minX, dy: backgroundFrame.minY))
|
||||
|
||||
let numberFrame = CGRect(origin: CGPoint(x: codeFrame.maxX + 10.0, y: 30.0), size: numberSize)
|
||||
let numberFrame = CGRect(origin: CGPoint(x: codeFrame.maxX + spacing, y: 30.0), size: numberSize)
|
||||
transition.updateFrame(node: self.phoneTargetNode, frame: numberFrame.offsetBy(dx: backgroundFrame.minX, dy: backgroundFrame.minY))
|
||||
|
||||
let textSize = self.textNode.updateLayout(backgroundSize)
|
||||
@ -972,6 +1021,10 @@ final class PhoneConfirmationController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
func dismissAnimated() {
|
||||
self.controllerNode.cancel()
|
||||
}
|
||||
|
||||
func transitionOut() {
|
||||
self.controllerNode.cancel()
|
||||
|
||||
|
@ -2136,21 +2136,21 @@ open class TextView: UIView {
|
||||
}
|
||||
}
|
||||
|
||||
if !line.strikethroughs.isEmpty {
|
||||
for strikethrough in line.strikethroughs {
|
||||
var textColor: UIColor?
|
||||
layout.attributedString?.enumerateAttributes(in: NSMakeRange(line.range.location, line.range.length), options: []) { attributes, range, _ in
|
||||
if range == strikethrough.range, let color = attributes[NSAttributedString.Key.foregroundColor] as? UIColor {
|
||||
textColor = color
|
||||
}
|
||||
}
|
||||
if let textColor = textColor {
|
||||
context.setFillColor(textColor.cgColor)
|
||||
}
|
||||
let frame = strikethrough.frame.offsetBy(dx: lineFrame.minX, dy: lineFrame.minY)
|
||||
context.fill(CGRect(x: frame.minX, y: frame.minY - 5.0, width: frame.width, height: 1.0))
|
||||
}
|
||||
}
|
||||
// if !line.strikethroughs.isEmpty {
|
||||
// for strikethrough in line.strikethroughs {
|
||||
// var textColor: UIColor?
|
||||
// layout.attributedString?.enumerateAttributes(in: NSMakeRange(line.range.location, line.range.length), options: []) { attributes, range, _ in
|
||||
// if range == strikethrough.range, let color = attributes[NSAttributedString.Key.foregroundColor] as? UIColor {
|
||||
// textColor = color
|
||||
// }
|
||||
// }
|
||||
// if let textColor = textColor {
|
||||
// context.setFillColor(textColor.cgColor)
|
||||
// }
|
||||
// let frame = strikethrough.frame.offsetBy(dx: lineFrame.minX, dy: lineFrame.minY)
|
||||
// context.fill(CGRect(x: frame.minX, y: frame.minY - 5.0, width: frame.width, height: 1.0))
|
||||
// }
|
||||
// }
|
||||
|
||||
if !line.spoilers.isEmpty {
|
||||
if layout.displaySpoilers {
|
||||
|
@ -10,6 +10,7 @@ import PersistentStringHash
|
||||
|
||||
private let productIdentifiers = [
|
||||
"org.telegram.telegramPremium.annual",
|
||||
"org.telegram.telegramPremium.semiannual",
|
||||
"org.telegram.telegramPremium.monthly",
|
||||
"org.telegram.telegramPremium.twelveMonths",
|
||||
"org.telegram.telegramPremium.sixMonths",
|
||||
@ -17,7 +18,7 @@ private let productIdentifiers = [
|
||||
]
|
||||
|
||||
private func isSubscriptionProductId(_ id: String) -> Bool {
|
||||
return id.hasSuffix(".monthly") || id.hasSuffix(".annual")
|
||||
return id.hasSuffix(".monthly") || id.hasSuffix(".annual") || id.hasSuffix(".semiannual")
|
||||
}
|
||||
|
||||
private extension NSDecimalNumber {
|
||||
@ -30,6 +31,22 @@ private extension NSDecimalNumber {
|
||||
raiseOnUnderflow: false,
|
||||
raiseOnDivideByZero: false))
|
||||
}
|
||||
|
||||
func prettyPrice() -> NSDecimalNumber {
|
||||
return self.multiplying(by: NSDecimalNumber(value: 2))
|
||||
.rounding(accordingToBehavior:
|
||||
NSDecimalNumberHandler(
|
||||
roundingMode: .plain,
|
||||
scale: Int16(0),
|
||||
raiseOnExactness: false,
|
||||
raiseOnOverflow: false,
|
||||
raiseOnUnderflow: false,
|
||||
raiseOnDivideByZero: false
|
||||
)
|
||||
)
|
||||
.dividing(by: NSDecimalNumber(value: 2))
|
||||
.subtracting(NSDecimalNumber(value: 0.01))
|
||||
}
|
||||
}
|
||||
|
||||
public final class InAppPurchaseManager: NSObject {
|
||||
@ -57,7 +74,7 @@ public final class InAppPurchaseManager: NSObject {
|
||||
} else if #available(iOS 11.2, *) {
|
||||
return self.skProduct.subscriptionPeriod != nil
|
||||
} else {
|
||||
return self.id.hasSuffix(".monthly") || self.id.hasSuffix(".annual")
|
||||
return self.id.hasSuffix(".monthly") || self.id.hasSuffix(".annual") || self.id.hasSuffix(".semiannual")
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,13 +83,27 @@ public final class InAppPurchaseManager: NSObject {
|
||||
}
|
||||
|
||||
public func pricePerMonth(_ monthsCount: Int) -> String {
|
||||
let price = self.skProduct.price.dividing(by: NSDecimalNumber(value: monthsCount)).round(2)
|
||||
let price = self.skProduct.price.dividing(by: NSDecimalNumber(value: monthsCount)).prettyPrice().round(2)
|
||||
return self.numberFormatter.string(from: price) ?? ""
|
||||
}
|
||||
|
||||
public func defaultPrice(_ value: NSDecimalNumber, monthsCount: Int) -> String {
|
||||
let price = value.multiplying(by: NSDecimalNumber(value: monthsCount)).round(2)
|
||||
return self.numberFormatter.string(from: price) ?? ""
|
||||
let prettierPrice = price
|
||||
.multiplying(by: NSDecimalNumber(value: 2))
|
||||
.rounding(accordingToBehavior:
|
||||
NSDecimalNumberHandler(
|
||||
roundingMode: .up,
|
||||
scale: Int16(0),
|
||||
raiseOnExactness: false,
|
||||
raiseOnOverflow: false,
|
||||
raiseOnUnderflow: false,
|
||||
raiseOnDivideByZero: false
|
||||
)
|
||||
)
|
||||
.dividing(by: NSDecimalNumber(value: 2))
|
||||
.subtracting(NSDecimalNumber(value: 0.01))
|
||||
return self.numberFormatter.string(from: prettierPrice) ?? ""
|
||||
}
|
||||
|
||||
public var priceValue: NSDecimalNumber {
|
||||
|
@ -548,7 +548,6 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
|
||||
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
).start(next: { [weak self] products, peer in
|
||||
if let strongSelf = self {
|
||||
|
||||
var gifts: [PremiumGiftProduct] = []
|
||||
for option in strongSelf.options {
|
||||
if let product = products.first(where: { $0.id == option.storeProductId }), !product.isSubscription {
|
||||
|
@ -305,6 +305,27 @@ struct PremiumIntroConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
private struct PremiumProduct: Equatable {
|
||||
let option: PremiumPromoConfiguration.PremiumProductOption
|
||||
let storeProduct: InAppPurchaseManager.Product
|
||||
|
||||
var id: String {
|
||||
return self.storeProduct.id
|
||||
}
|
||||
|
||||
var months: Int32 {
|
||||
return self.option.months
|
||||
}
|
||||
|
||||
var price: String {
|
||||
return self.storeProduct.price
|
||||
}
|
||||
|
||||
var pricePerMonth: String {
|
||||
return self.storeProduct.pricePerMonth(Int(self.months))
|
||||
}
|
||||
}
|
||||
|
||||
final class PremiumOptionComponent: CombinedComponent {
|
||||
let title: String
|
||||
let subtitle: String
|
||||
@ -419,7 +440,7 @@ final class PremiumOptionComponent: CombinedComponent {
|
||||
)
|
||||
|
||||
var spacing: CGFloat = 0.0
|
||||
var subtitleHeight: CGFloat = 0.0
|
||||
var subtitleSize = CGSize()
|
||||
if !component.subtitle.isEmpty {
|
||||
spacing = 2.0
|
||||
|
||||
@ -447,7 +468,7 @@ final class PremiumOptionComponent: CombinedComponent {
|
||||
context.add(subtitle
|
||||
.position(CGPoint(x: insets.left + subtitle.size.width / 2.0, y: insets.top + title.size.height + spacing + subtitle.size.height / 2.0))
|
||||
)
|
||||
subtitleHeight = subtitle.size.height
|
||||
subtitleSize = subtitle.size
|
||||
|
||||
insets.top -= 2.0
|
||||
insets.bottom -= 2.0
|
||||
@ -512,10 +533,19 @@ final class PremiumOptionComponent: CombinedComponent {
|
||||
.position(CGPoint(x: insets.left + title.size.width / 2.0, y: insets.top + title.size.height / 2.0))
|
||||
)
|
||||
|
||||
let size = CGSize(width: context.availableSize.width, height: insets.top + title.size.height + spacing + subtitleHeight + insets.bottom)
|
||||
let size = CGSize(width: context.availableSize.width, height: insets.top + title.size.height + spacing + subtitleSize.height + insets.bottom)
|
||||
|
||||
let distance = context.availableSize.width - insets.left - insets.right - label.size.width - subtitleSize.width
|
||||
|
||||
let labelY: CGFloat
|
||||
if distance > 8.0 {
|
||||
labelY = size.height / 2.0
|
||||
} else {
|
||||
labelY = insets.top + title.size.height / 2.0
|
||||
}
|
||||
|
||||
context.add(label
|
||||
.position(CGPoint(x: context.availableSize.width - insets.right - label.size.width / 2.0, y: size.height / 2.0))
|
||||
.position(CGPoint(x: context.availableSize.width - insets.right - label.size.width / 2.0, y: labelY))
|
||||
)
|
||||
|
||||
context.add(check
|
||||
@ -970,20 +1000,22 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
let source: PremiumSource
|
||||
let isPremium: Bool?
|
||||
let otherPeerName: String?
|
||||
let products: [InAppPurchaseManager.Product]?
|
||||
let products: [PremiumProduct]?
|
||||
let selectedProductId: String?
|
||||
let promoConfiguration: PremiumPromoConfiguration?
|
||||
let present: (ViewController) -> Void
|
||||
let selectProduct: (String) -> Void
|
||||
let buy: () -> Void
|
||||
let updateIsFocused: (Bool) -> Void
|
||||
|
||||
init(context: AccountContext, source: PremiumSource, isPremium: Bool?, otherPeerName: String?, products: [InAppPurchaseManager.Product]?, selectedProductId: String?, present: @escaping (ViewController) -> Void, selectProduct: @escaping (String) -> Void, buy: @escaping () -> Void, updateIsFocused: @escaping (Bool) -> Void) {
|
||||
init(context: AccountContext, source: PremiumSource, isPremium: Bool?, otherPeerName: String?, products: [PremiumProduct]?, selectedProductId: String?, promoConfiguration: PremiumPromoConfiguration?, present: @escaping (ViewController) -> Void, selectProduct: @escaping (String) -> Void, buy: @escaping () -> Void, updateIsFocused: @escaping (Bool) -> Void) {
|
||||
self.context = context
|
||||
self.source = source
|
||||
self.isPremium = isPremium
|
||||
self.otherPeerName = otherPeerName
|
||||
self.products = products
|
||||
self.selectedProductId = selectedProductId
|
||||
self.promoConfiguration = promoConfiguration
|
||||
self.present = present
|
||||
self.selectProduct = selectProduct
|
||||
self.buy = buy
|
||||
@ -1009,6 +1041,9 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
if lhs.selectedProductId != rhs.selectedProductId {
|
||||
return false
|
||||
}
|
||||
if lhs.promoConfiguration != rhs.promoConfiguration {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@ -1016,15 +1051,14 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
final class State: ComponentState {
|
||||
private let context: AccountContext
|
||||
|
||||
var products: [InAppPurchaseManager.Product]?
|
||||
var products: [PremiumProduct]?
|
||||
var selectedProductId: String?
|
||||
|
||||
var isPremium: Bool?
|
||||
|
||||
private var disposable: Disposable?
|
||||
private(set) var configuration = PremiumIntroConfiguration.defaultValue
|
||||
private(set) var promoConfiguration: PremiumPromoConfiguration?
|
||||
|
||||
|
||||
private var stickersDisposable: Disposable?
|
||||
private var preloadDisposableSet = DisposableSet()
|
||||
|
||||
@ -1042,13 +1076,11 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
super.init()
|
||||
|
||||
self.disposable = (context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Configuration.App(),
|
||||
TelegramEngine.EngineData.Item.Configuration.PremiumPromo()
|
||||
TelegramEngine.EngineData.Item.Configuration.App()
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] appConfiguration, promoConfiguration in
|
||||
|> deliverOnMainQueue).start(next: { [weak self] appConfiguration in
|
||||
if let strongSelf = self {
|
||||
strongSelf.configuration = PremiumIntroConfiguration.with(appConfiguration: appConfiguration)
|
||||
strongSelf.promoConfiguration = promoConfiguration
|
||||
strongSelf.updated(transition: .immediate)
|
||||
|
||||
if let identifier = source.identifier {
|
||||
@ -1070,10 +1102,6 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
addAppLogEvent(postbox: strongSelf.context.account.postbox, type: "premium.promo_screen_show", data: json)
|
||||
}
|
||||
}
|
||||
|
||||
for (_, video) in promoConfiguration.videos {
|
||||
strongSelf.preloadDisposableSet.add(preloadVideoResource(postbox: context.account.postbox, resourceReference: .standalone(resource: video.resource), duration: 3.0).start())
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -1253,7 +1281,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
|
||||
let shortestOptionPrice: (Int64, NSDecimalNumber)
|
||||
if let product = products.first(where: { $0.id.hasSuffix(".monthly") }) {
|
||||
shortestOptionPrice = (Int64(Float(product.priceCurrencyAndAmount.amount)), product.priceValue)
|
||||
shortestOptionPrice = (Int64(Float(product.storeProduct.priceCurrencyAndAmount.amount)), product.storeProduct.priceValue)
|
||||
} else {
|
||||
shortestOptionPrice = (1, NSDecimalNumber(decimal: 1))
|
||||
}
|
||||
@ -1261,16 +1289,17 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
var i = 0
|
||||
for product in products {
|
||||
let giftTitle: String
|
||||
let months: Float
|
||||
let months = product.months
|
||||
|
||||
if product.id.hasSuffix(".monthly") {
|
||||
giftTitle = strings.Premium_Monthly
|
||||
months = 1
|
||||
} else if product.id.hasSuffix(".semiannual") {
|
||||
giftTitle = strings.Premium_Semiannual
|
||||
} else {
|
||||
giftTitle = strings.Premium_Annual
|
||||
months = 12
|
||||
}
|
||||
|
||||
let discountValue = Int((1.0 - Float(product.priceCurrencyAndAmount.amount) / months / Float(shortestOptionPrice.0)) * 100.0)
|
||||
let discountValue = Int((1.0 - Float(product.storeProduct.priceCurrencyAndAmount.amount) / Float(months) / Float(shortestOptionPrice.0)) * 100.0)
|
||||
let discount: String
|
||||
if discountValue > 0 {
|
||||
discount = "-\(discountValue)%"
|
||||
@ -1278,12 +1307,12 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
discount = ""
|
||||
}
|
||||
|
||||
let defaultPrice = product.defaultPrice(shortestOptionPrice.1, monthsCount: Int(months))
|
||||
let defaultPrice = product.storeProduct.defaultPrice(shortestOptionPrice.1, monthsCount: Int(months))
|
||||
|
||||
var subtitle = ""
|
||||
var pricePerMonth = product.price
|
||||
if months > 1 {
|
||||
pricePerMonth = product.pricePerMonth(Int(months))
|
||||
pricePerMonth = product.storeProduct.pricePerMonth(Int(months))
|
||||
|
||||
if discountValue > 0 {
|
||||
subtitle = "**\(defaultPrice)** \(product.price)"
|
||||
@ -1552,7 +1581,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
||||
let termsString: MultilineTextComponent.TextContent
|
||||
if isGiftView {
|
||||
termsString = .plain(NSAttributedString())
|
||||
} else if let promoConfiguration = context.state.promoConfiguration {
|
||||
} else if let promoConfiguration = context.component.promoConfiguration {
|
||||
let attributedString = stringWithAppliedEntities(promoConfiguration.status, entities: promoConfiguration.statusEntities, baseColor: termsTextColor, linkColor: environment.theme.list.itemAccentColor, baseFont: termsFont, linkFont: termsFont, boldFont: boldTermsFont, italicFont: italicTermsFont, boldItalicFont: boldItalicTermsFont, fixedFont: monospaceTermsFont, blockQuoteFont: termsFont, message: nil)
|
||||
termsString = .plain(attributedString)
|
||||
} else {
|
||||
@ -1723,8 +1752,10 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
|
||||
var inProgress = false
|
||||
|
||||
var products: [InAppPurchaseManager.Product]?
|
||||
var selectedProductId: String?
|
||||
private(set) var promoConfiguration: PremiumPromoConfiguration?
|
||||
|
||||
private(set) var products: [PremiumProduct]?
|
||||
private(set) var selectedProductId: String?
|
||||
|
||||
var isPremium: Bool?
|
||||
var otherPeerName: String?
|
||||
@ -1740,6 +1771,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
private var disposable: Disposable?
|
||||
private var paymentDisposable = MetaDisposable()
|
||||
private var activationDisposable = MetaDisposable()
|
||||
private var preloadDisposableSet = DisposableSet()
|
||||
|
||||
var price: String? {
|
||||
return self.products?.first(where: { $0.id == self.selectedProductId })?.price
|
||||
@ -1792,20 +1824,37 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
self.disposable = combineLatest(
|
||||
queue: Queue.mainQueue(),
|
||||
availableProducts,
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Configuration.PremiumPromo()),
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
|> map { peer -> Bool in
|
||||
return peer?.isPremium ?? false
|
||||
},
|
||||
otherPeerName
|
||||
).start(next: { [weak self] products, isPremium, otherPeerName in
|
||||
).start(next: { [weak self] availableProducts, promoConfiguration, isPremium, otherPeerName in
|
||||
if let strongSelf = self {
|
||||
strongSelf.promoConfiguration = promoConfiguration
|
||||
|
||||
let hadProducts = strongSelf.products != nil
|
||||
strongSelf.products = products.filter { $0.isSubscription }
|
||||
if !hadProducts {
|
||||
strongSelf.selectedProductId = strongSelf.products?.last?.id
|
||||
|
||||
var products: [PremiumProduct] = []
|
||||
for option in promoConfiguration.premiumProductOptions {
|
||||
if let product = availableProducts.first(where: { $0.id == option.storeProductId }), product.isSubscription {
|
||||
products.append(PremiumProduct(option: option, storeProduct: product))
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.products = products
|
||||
strongSelf.isPremium = isPremium
|
||||
strongSelf.otherPeerName = otherPeerName
|
||||
|
||||
if !hadProducts {
|
||||
strongSelf.selectedProductId = strongSelf.products?.last?.id
|
||||
|
||||
for (_, video) in promoConfiguration.videos {
|
||||
strongSelf.preloadDisposableSet.add(preloadVideoResource(postbox: context.account.postbox, resourceReference: .standalone(resource: video.resource), duration: 3.0).start())
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.updated(transition: .immediate)
|
||||
}
|
||||
})
|
||||
@ -1833,6 +1882,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
self.paymentDisposable.dispose()
|
||||
self.activationDisposable.dispose()
|
||||
self.emojiFileDisposable?.dispose()
|
||||
self.preloadDisposableSet.dispose()
|
||||
}
|
||||
|
||||
func buy() {
|
||||
@ -1851,7 +1901,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
|> deliverOnMainQueue).start(next: { [weak self] available in
|
||||
if let strongSelf = self {
|
||||
if available {
|
||||
strongSelf.paymentDisposable.set((inAppPurchaseManager.buyProduct(premiumProduct)
|
||||
strongSelf.paymentDisposable.set((inAppPurchaseManager.buyProduct(premiumProduct.storeProduct)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||
if let strongSelf = self, case .purchased = status {
|
||||
strongSelf.activationDisposable.set((strongSelf.context.account.postbox.peerView(id: strongSelf.context.account.peerId)
|
||||
@ -2153,6 +2203,7 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
|
||||
otherPeerName: state.otherPeerName,
|
||||
products: state.products,
|
||||
selectedProductId: state.selectedProductId,
|
||||
promoConfiguration: state.promoConfiguration,
|
||||
present: context.component.present,
|
||||
selectProduct: { [weak state] productId in
|
||||
state?.selectProduct(productId)
|
||||
|
@ -539,8 +539,18 @@ private func privacyAndSecurityControllerEntries(
|
||||
return entries
|
||||
}
|
||||
|
||||
class PrivacyAndSecurityControllerImpl: ItemListController {
|
||||
|
||||
class PrivacyAndSecurityControllerImpl: ItemListController, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding {
|
||||
var authorizationCompletion: (ASAuthorizationCredential) -> Void = { _ in }
|
||||
|
||||
@available(iOS 13.0, *)
|
||||
public func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
|
||||
self.authorizationCompletion(authorization)
|
||||
}
|
||||
|
||||
@available(iOS 13.0, *)
|
||||
public func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
|
||||
return self.view.window!
|
||||
}
|
||||
}
|
||||
|
||||
public func privacyAndSecurityController(context: AccountContext, initialSettings: AccountPrivacySettings? = nil, updatedSettings: ((AccountPrivacySettings?) -> Void)? = nil, updatedBlockedPeers: ((BlockedPeersContext?) -> Void)? = nil, updatedHasTwoStepAuth: ((Bool) -> Void)? = nil, focusOnItemTag: PrivacyAndSecurityEntryTag? = nil, activeSessionsContext: ActiveSessionsContext? = nil, webSessionsContext: WebSessionsContext? = nil, blockedPeersContext: BlockedPeersContext? = nil, hasTwoStepAuth: Bool? = nil, loginEmailPattern: Signal<String?, NoError>? = nil) -> ViewController {
|
||||
@ -1083,6 +1093,27 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting
|
||||
let codeController = AuthorizationSequenceCodeEntryController(presentationData: presentationData, openUrl: { _ in }, back: {
|
||||
dismissCodeControllerImpl?()
|
||||
})
|
||||
|
||||
let emailChangeCompletion = { [weak codeController] in
|
||||
codeController?.animateSuccess()
|
||||
Queue.mainQueue().after(0.75) {
|
||||
if let navigationController = getNavigationControllerImpl?() {
|
||||
let controllers = navigationController.viewControllers.filter { controller in
|
||||
if controller is AuthorizationSequenceEmailEntryController || controller is AuthorizationSequenceCodeEntryController {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
|
||||
navigationController.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .emoji(name: "IntroLetter", text: presentationData.strings.Login_EmailChanged), elevatedLayout: false, animateInAsReplacement: false, action: { _ in
|
||||
return false
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
codeController.loginWithCode = { [weak codeController] code in
|
||||
actionsDisposable.add((verifyLoginEmailChange(account: context.account, code: .emailCode(code))
|
||||
|> deliverOnMainQueue).start(error: { error in
|
||||
@ -1120,39 +1151,57 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting
|
||||
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]))
|
||||
}
|
||||
}
|
||||
}, completed: { [weak codeController] in
|
||||
codeController?.animateSuccess()
|
||||
Queue.mainQueue().after(0.75) {
|
||||
if let navigationController = getNavigationControllerImpl?() {
|
||||
let controllers = navigationController.viewControllers.filter { controller in
|
||||
if controller is AuthorizationSequenceEmailEntryController || controller is AuthorizationSequenceCodeEntryController {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
|
||||
navigationController.presentOverlay(controller: UndoOverlayController(presentationData: presentationData, content: .emoji(name: "IntroLetter", text: presentationData.strings.Login_EmailChanged), elevatedLayout: false, animateInAsReplacement: false, action: { _ in
|
||||
return false
|
||||
}))
|
||||
}
|
||||
}
|
||||
}, completed: {
|
||||
emailChangeCompletion()
|
||||
}))
|
||||
}
|
||||
codeController.signInWithApple = {
|
||||
// if #available(iOS 13.0, *) {
|
||||
// let appleIdProvider = ASAuthorizationAppleIDProvider()
|
||||
// let passwordProvider = ASAuthorizationPasswordProvider()
|
||||
// let request = appleIdProvider.createRequest()
|
||||
//
|
||||
// let passwordRequest = passwordProvider.createRequest()
|
||||
//
|
||||
// let authorizationController = ASAuthorizationController(authorizationRequests: [request, passwordRequest])
|
||||
// authorizationController.delegate = strongSelf
|
||||
// authorizationController.presentationContextProvider = strongSelf
|
||||
// authorizationController.performRequests()
|
||||
// }
|
||||
codeController.signInWithApple = { [weak controller, weak codeController] in
|
||||
if #available(iOS 13.0, *) {
|
||||
let appleIdProvider = ASAuthorizationAppleIDProvider()
|
||||
let passwordProvider = ASAuthorizationPasswordProvider()
|
||||
let request = appleIdProvider.createRequest()
|
||||
|
||||
let passwordRequest = passwordProvider.createRequest()
|
||||
|
||||
let authorizationController = ASAuthorizationController(authorizationRequests: [request, passwordRequest])
|
||||
authorizationController.delegate = controller
|
||||
authorizationController.presentationContextProvider = controller
|
||||
authorizationController.performRequests()
|
||||
|
||||
controller.authorizationCompletion = { [weak controller, weak codeController] credentials in
|
||||
switch authorization.credential {
|
||||
case let appleIdCredential as ASAuthorizationAppleIDCredential:
|
||||
guard let tokenData = appleIdCredential.identityToken, let token = String(data: tokenData, encoding: .utf8) else {
|
||||
codeController?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
return
|
||||
}
|
||||
actionsDisposable.add((verifyLoginEmailChange(account: context.account, code: .appleToken(token))
|
||||
|> deliverOnMainQueue).start(error: { error in
|
||||
let text: String
|
||||
switch error {
|
||||
case .limitExceeded:
|
||||
text = presentationData.strings.Login_CodeFloodError
|
||||
case .generic, .codeExpired:
|
||||
text = presentationData.strings.Login_UnknownError
|
||||
case .invalidCode:
|
||||
text = presentationData.strings.Login_InvalidCodeError
|
||||
case .timeout:
|
||||
text = presentationData.strings.Login_NetworkError
|
||||
case .invalidEmailToken:
|
||||
text = presentationData.strings.Login_InvalidEmailTokenError
|
||||
case .emailNotAllowed:
|
||||
text = presentationData.strings.Login_EmailNotAllowedError
|
||||
}
|
||||
codeController?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}, completed: { [weak controller] in
|
||||
controller?.authorizationCompletion = nil
|
||||
emailChangeCompletion()
|
||||
}))
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
codeController.updateData(number: "", email: email, codeType: .email(emailPattern: "", length: data.length, nextPhoneLoginDate: nil, appleSignInAllowed: false, setup: true), nextType: nil, timeout: nil, termsOfService: nil)
|
||||
pushControllerImpl?(codeController, true)
|
||||
|
@ -432,7 +432,7 @@ public func verifyLoginEmailChange(account: Account, code: AuthorizationCode.Ema
|
||||
}
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<Never, AuthorizationEmailVerificationError> in
|
||||
return .never()
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user