Authorization improvements

This commit is contained in:
Ilya Laktyushin 2022-08-24 15:11:06 +02:00
parent 6550313056
commit a28f744eb4
31 changed files with 720 additions and 436 deletions

View File

@ -7977,3 +7977,21 @@ Sorry for the inconvenience.";
"Premium.EmojiStatusText" = "Emoji status is a premium feature.\n Other features included in **Telegram Premium**:"; "Premium.EmojiStatusText" = "Emoji status is a premium feature.\n Other features included in **Telegram Premium**:";
"Login.SelectCountry" = "Country"; "Login.SelectCountry" = "Country";
"Login.Or" = "or";
"Login.Continue" = "Continue";
"Login.EnterCodeSMSTitle" = "Enter Code";
"Login.EnterCodeSMSText" = "We've sent and SMS with an activation code to your phone **%@**.";
"Login.SendCodeAsSMS" = "Send the code as an SMS";
"Login.EnterCodeTelegramTitle" = "Enter Code";
"Login.EnterCodeTelegramText" = "We've sent the code to the **Telegram app** for %@ on your other device.";
"Login.AddEmailTitle" = "Add Email";
"Login.AddEmailText" = "Please enter your valid email address to protect your account.";
"Login.AddEmailPlaceholder" = "Enter your email";
"Login.EnterCodeEmailTitle" = "Check Your Email";
"Login.EnterCodeEmailText" = "Please enter the code we have sent to your email %@.";
"Login.WrongCodeError" = "Wrong code, please try again.";

View File

@ -13,4 +13,6 @@ public protocol ChatListController: ViewController {
func deactivateSearch(animated: Bool) func deactivateSearch(animated: Bool)
func activateCompose() func activateCompose()
func maybeAskForPeerChatRemoval(peer: EngineRenderedPeer, joined: Bool, deleteGloballyIfPossible: Bool, completion: @escaping (Bool) -> Void, removed: @escaping () -> Void) func maybeAskForPeerChatRemoval(peer: EngineRenderedPeer, joined: Bool, deleteGloballyIfPossible: Bool, completion: @escaping (Bool) -> Void, removed: @escaping () -> Void)
func playSignUpCompletedAnimation()
} }

View File

@ -75,7 +75,7 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
self.clipNode = ASDisplayNode() self.clipNode = ASDisplayNode()
var controllerRemovedImpl: ((ViewController) -> Void)? var controllerRemovedImpl: ((ViewController) -> Void)?
self.container = NavigationContainer(controllerRemoved: { c in self.container = NavigationContainer(isFlat: false, controllerRemoved: { c in
controllerRemovedImpl?(c) controllerRemovedImpl?(c)
}) })
self.container.clipsToBounds = true self.container.clipsToBounds = true

View File

@ -6,15 +6,17 @@ import TelegramPresentationData
import TextFormat import TextFormat
import Markdown import Markdown
public func authorizationCurrentOptionText(_ type: SentAuthorizationCodeType, strings: PresentationStrings, primaryColor: UIColor, accentColor: UIColor) -> NSAttributedString { public func authorizationCurrentOptionText(_ type: SentAuthorizationCodeType, phoneNumber: String, email: String?, strings: PresentationStrings, primaryColor: UIColor, accentColor: UIColor) -> NSAttributedString {
let fontSize: CGFloat = 17.0 let fontSize: CGFloat = 17.0
let body = MarkdownAttributeSet(font: Font.regular(fontSize), textColor: primaryColor)
let bold = MarkdownAttributeSet(font: Font.semibold(fontSize), textColor: primaryColor)
let attributes = MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in nil })
switch type { switch type {
case .sms: case .sms:
return NSAttributedString(string: strings.Login_CodeSentSms, font: Font.regular(fontSize), textColor: primaryColor, paragraphAlignment: .center) return parseMarkdownIntoAttributedString(strings.Login_EnterCodeSMSText(phoneNumber).string, attributes: attributes, textAlignment: .center)
case .otherSession: case .otherSession:
let body = MarkdownAttributeSet(font: Font.regular(fontSize), textColor: primaryColor) return parseMarkdownIntoAttributedString(strings.Login_EnterCodeTelegramText(phoneNumber).string, attributes: attributes, textAlignment: .center)
let bold = MarkdownAttributeSet(font: Font.semibold(fontSize), textColor: primaryColor)
return parseMarkdownIntoAttributedString(strings.Login_CodeSentInternal, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in nil }), textAlignment: .center)
case .missedCall: case .missedCall:
let body = MarkdownAttributeSet(font: Font.regular(fontSize), textColor: primaryColor) let body = MarkdownAttributeSet(font: Font.regular(fontSize), textColor: primaryColor)
let bold = MarkdownAttributeSet(font: Font.semibold(fontSize), textColor: primaryColor) let bold = MarkdownAttributeSet(font: Font.semibold(fontSize), textColor: primaryColor)
@ -26,8 +28,7 @@ public func authorizationCurrentOptionText(_ type: SentAuthorizationCodeType, st
case .emailSetupRequired: case .emailSetupRequired:
return NSAttributedString(string: "", font: Font.regular(fontSize), textColor: primaryColor, paragraphAlignment: .center) return NSAttributedString(string: "", font: Font.regular(fontSize), textColor: primaryColor, paragraphAlignment: .center)
case let .email(emailPattern, _, _, _, _): case let .email(emailPattern, _, _, _, _):
//TODO: localize let mutableString = NSAttributedString(string: strings.Login_EnterCodeEmailText(email ?? emailPattern).string, font: Font.regular(fontSize), textColor: primaryColor, paragraphAlignment: .center).mutableCopy() as! NSMutableAttributedString
let mutableString = NSAttributedString(string: "Please enter the code we have sent to your email \(emailPattern).", font: Font.regular(fontSize), textColor: primaryColor, paragraphAlignment: .center).mutableCopy() as! NSMutableAttributedString
let range = (mutableString.string as NSString).range(of: "*******") let range = (mutableString.string as NSString).range(of: "*******")
if range.location != NSNotFound { if range.location != NSNotFound {
mutableString.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler), value: true, range: range) mutableString.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler), value: true, range: range)

View File

@ -30,6 +30,7 @@ import ComponentFlow
import LottieAnimationComponent import LottieAnimationComponent
import ProgressIndicatorComponent import ProgressIndicatorComponent
import PremiumUI import PremiumUI
import ConfettiEffect
private func fixListNodeScrolling(_ listNode: ListView, searchNode: NavigationBarSearchContentNode) -> Bool { private func fixListNodeScrolling(_ listNode: ListView, searchNode: NavigationBarSearchContentNode) -> Bool {
if listNode.scroller.isDragging { if listNode.scroller.isDragging {
@ -1527,7 +1528,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
override public func viewDidAppear(_ animated: Bool) { override public func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
self.didAppear = true self.didAppear = true
self.chatListDisplayNode.containerNode.updateEnableAdjacentFilterLoading(true) self.chatListDisplayNode.containerNode.updateEnableAdjacentFilterLoading(true)
@ -3405,6 +3406,17 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
strongSelf.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller) strongSelf.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
}) })
} }
private var playedSignUpCompletedAnimation = false
public func playSignUpCompletedAnimation() {
guard !self.playedSignUpCompletedAnimation else {
return
}
self.playedSignUpCompletedAnimation = true
Queue.mainQueue().after(0.3) {
self.view.addSubview(ConfettiView(frame: self.view.bounds))
}
}
} }
private final class ChatListTabBarContextExtractedContentSource: ContextExtractedContentSource { private final class ChatListTabBarContextExtractedContentSource: ContextExtractedContentSource {

View File

@ -2,23 +2,30 @@ import Foundation
import UIKit import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import SwiftSignalKit
import PhoneNumberFormat import PhoneNumberFormat
public final class CodeInputView: ASDisplayNode, UITextFieldDelegate { public final class CodeInputView: ASDisplayNode, UITextFieldDelegate {
public struct Theme: Equatable { public struct Theme: Equatable {
public var inactiveBorder: UInt32 public var inactiveBorder: UInt32
public var activeBorder: UInt32 public var activeBorder: UInt32
public var succeedBorder: UInt32
public var failedBorder: UInt32
public var foreground: UInt32 public var foreground: UInt32
public var isDark: Bool public var isDark: Bool
public init( public init(
inactiveBorder: UInt32, inactiveBorder: UInt32,
activeBorder: UInt32, activeBorder: UInt32,
succeedBorder: UInt32,
failedBorder: UInt32,
foreground: UInt32, foreground: UInt32,
isDark: Bool isDark: Bool
) { ) {
self.inactiveBorder = inactiveBorder self.inactiveBorder = inactiveBorder
self.activeBorder = activeBorder self.activeBorder = activeBorder
self.succeedBorder = succeedBorder
self.failedBorder = failedBorder
self.foreground = foreground self.foreground = foreground
self.isDark = isDark self.isDark = isDark
} }
@ -71,7 +78,7 @@ public final class CodeInputView: ASDisplayNode, UITextFieldDelegate {
} }
} }
func update(textColor: UInt32, text: String, size: CGSize, fontSize: CGFloat, animated: Bool) { func update(textColor: UInt32, text: String, size: CGSize, fontSize: CGFloat, animated: Bool, delay: Double? = nil) {
let previousText = self.text let previousText = self.text
self.text = text self.text = text
@ -83,10 +90,10 @@ public final class CodeInputView: ASDisplayNode, UITextFieldDelegate {
} else { } else {
if let copyView = self.textNode.view.snapshotContentTree() { if let copyView = self.textNode.view.snapshotContentTree() {
self.view.insertSubview(copyView, at: 0) self.view.insertSubview(copyView, at: 0)
copyView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak copyView] _ in copyView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, delay: delay ?? 0.0, removeOnCompletion: false, completion: { [weak copyView] _ in
copyView?.removeFromSuperview() copyView?.removeFromSuperview()
}) })
copyView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: size.height / 2.0), duration: 0.2, removeOnCompletion: false, additive: true) copyView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: size.height / 2.0), duration: 0.2, delay: delay ?? 0.0, removeOnCompletion: false, additive: true)
} }
} }
} }
@ -160,6 +167,28 @@ public final class CodeInputView: ASDisplayNode, UITextFieldDelegate {
} }
} }
private var isSucceed = false
private var isFailed = false
private var isResetting = false
public func animateError() {
self.isFailed = true
self.updateItemViews(animated: true)
Queue.mainQueue().after(0.85, {
self.textValue = ""
self.isResetting = true
self.updateItemViews(animated: true)
self.isResetting = false
self.textField.text = ""
self.isFailed = false
self.updateItemViews(animated: true)
})
}
public func animateSuccess() {
self.isSucceed = true
self.updateItemViews(animated: true)
}
@objc func textFieldChanged(_ textField: UITextField) { @objc func textFieldChanged(_ textField: UITextField) {
self.textValue = textField.text ?? "" self.textValue = textField.text ?? ""
self.updateItemViews(animated: true) self.updateItemViews(animated: true)
@ -170,6 +199,11 @@ public final class CodeInputView: ASDisplayNode, UITextFieldDelegate {
guard let count = self.count else { guard let count = self.count else {
return false return false
} }
guard !self.isFailed else {
return false
}
var text = textField.text ?? "" var text = textField.text ?? ""
guard let stringRange = Range(range, in: text) else { guard let stringRange = Range(range, in: text) else {
return false return false
@ -220,6 +254,7 @@ public final class CodeInputView: ASDisplayNode, UITextFieldDelegate {
return return
} }
var delay: Double = 0.0
for i in 0 ..< self.itemViews.count { for i in 0 ..< self.itemViews.count {
let itemView = self.itemViews[i] let itemView = self.itemViews[i]
let itemSize = itemView.bounds.size let itemSize = itemView.bounds.size
@ -233,14 +268,26 @@ public final class CodeInputView: ASDisplayNode, UITextFieldDelegate {
fontSize = floor(21.0 * height / 28.0) fontSize = floor(21.0 * height / 28.0)
} }
itemView.update(borderColor: self.focusIndex == i ? theme.activeBorder : theme.inactiveBorder, isHighlighted: self.focusIndex == i) let borderColor: UInt32
if self.isSucceed {
borderColor = theme.succeedBorder
} else if self.isFailed {
borderColor = theme.failedBorder
} else {
borderColor = self.focusIndex == i ? theme.activeBorder : theme.inactiveBorder
}
itemView.update(borderColor: borderColor, isHighlighted: self.focusIndex == i)
let itemText: String let itemText: String
if i < self.textValue.count { if i < self.textValue.count {
itemText = String(self.textValue[self.textValue.index(self.textValue.startIndex, offsetBy: i)]) itemText = String(self.textValue[self.textValue.index(self.textValue.startIndex, offsetBy: i)])
} else { } else {
itemText = "" itemText = ""
} }
itemView.update(textColor: theme.foreground, text: itemText, size: itemSize, fontSize: fontSize, animated: animated) itemView.update(textColor: theme.foreground, text: itemText, size: itemSize, fontSize: fontSize, animated: animated, delay: delay)
if self.isResetting {
delay += 0.05
}
} }
} }
@ -291,7 +338,17 @@ public final class CodeInputView: ASDisplayNode, UITextFieldDelegate {
self.itemViews.append(itemView) self.itemViews.append(itemView)
self.addSubnode(itemView) self.addSubnode(itemView)
} }
itemView.update(borderColor: self.focusIndex == i ? theme.activeBorder : theme.inactiveBorder, isHighlighted: self.focusIndex == i)
let borderColor: UInt32
if self.isSucceed {
borderColor = theme.succeedBorder
} else if self.isFailed {
borderColor = theme.failedBorder
} else {
borderColor = self.focusIndex == i ? theme.activeBorder : theme.inactiveBorder
}
itemView.update(borderColor: borderColor, isHighlighted: self.focusIndex == i)
let itemText: String let itemText: String
if i < self.textValue.count { if i < self.textValue.count {
itemText = String(self.textValue[self.textValue.index(self.textValue.startIndex, offsetBy: i)]) itemText = String(self.textValue[self.textValue.index(self.textValue.startIndex, offsetBy: i)])

View File

@ -43,11 +43,17 @@ private func loadCountryCodes() -> [Country] {
let countryId = String(data[codeRange.upperBound ..< idRange.lowerBound]) let countryId = String(data[codeRange.upperBound ..< idRange.lowerBound])
let maybeNameRange = data.range(of: endOfLine, options: [], range: idRange.upperBound ..< data.endIndex) guard let patternRange = data.range(of: delimiter, options: [], range: idRange.upperBound ..< data.endIndex) else {
break
}
let pattern = String(data[idRange.upperBound ..< patternRange.lowerBound])
let maybeNameRange = data.range(of: endOfLine, options: [], range: patternRange.upperBound ..< data.endIndex)
let countryName = locale.localizedString(forIdentifier: countryId) ?? "" let countryName = locale.localizedString(forIdentifier: countryId) ?? ""
if let _ = Int(countryCode) { if let _ = Int(countryCode) {
let code = Country.CountryCode(code: countryCode, prefixes: [], patterns: []) let code = Country.CountryCode(code: countryCode, prefixes: [], patterns: !pattern.isEmpty ? [pattern] : [])
let country = Country(id: countryId, name: countryName, localizedName: nil, countryCodes: [code], hidden: false) let country = Country(id: countryId, name: countryName, localizedName: nil, countryCodes: [code], hidden: false)
result.append(country) result.append(country)
countriesByPrefix["\(code.code)"] = (country, code) countriesByPrefix["\(code.code)"] = (country, code)
@ -86,6 +92,7 @@ public func loadServerCountryCodes(accountManager: AccountManager<TelegramAccoun
} }
} }
countryCodesByPrefix = countriesByPrefix countryCodesByPrefix = countriesByPrefix
Queue.mainQueue().async { Queue.mainQueue().async {
completion() completion()
} }

View File

@ -38,7 +38,11 @@ private func loadCountryCodes() -> [(String, Int)] {
let countryId = String(data[codeRange.upperBound ..< idRange.lowerBound]) let countryId = String(data[codeRange.upperBound ..< idRange.lowerBound])
let maybeNameRange = data.range(of: endOfLine, options: [], range: idRange.upperBound ..< data.endIndex) guard let patternRange = data.range(of: delimiter, options: [], range: idRange.upperBound ..< data.endIndex) else {
break
}
let maybeNameRange = data.range(of: endOfLine, options: [], range: patternRange.upperBound ..< data.endIndex)
if let countryCodeInt = Int(countryCode) { if let countryCodeInt = Int(countryCode) {
result.append((countryId, countryCodeInt)) result.append((countryId, countryCodeInt))

View File

@ -57,9 +57,13 @@ private func loadCountriesInfo() -> [(Int, String, String)] {
let countryId = String(data[codeRange.upperBound ..< idRange.lowerBound]) let countryId = String(data[codeRange.upperBound ..< idRange.lowerBound])
guard let patternRange = data.range(of: delimiter, options: [], range: idRange.upperBound ..< data.endIndex) else {
break
}
let countryName: String let countryName: String
let nameRange1 = data.range(of: endOfLine1, options: [], range: idRange.upperBound ..< data.endIndex) let nameRange1 = data.range(of: endOfLine1, options: [], range: patternRange.upperBound ..< data.endIndex)
let nameRange2 = data.range(of: endOfLine2, options: [], range: idRange.upperBound ..< data.endIndex) let nameRange2 = data.range(of: endOfLine2, options: [], range: patternRange.upperBound ..< data.endIndex)
var nameRange: Range<String.Index>? var nameRange: Range<String.Index>?
if let nameRange1 = nameRange1, let nameRange2 = nameRange2 { if let nameRange1 = nameRange1, let nameRange2 = nameRange2 {
if nameRange1.lowerBound < nameRange2.lowerBound { if nameRange1.lowerBound < nameRange2.lowerBound {
@ -71,10 +75,10 @@ private func loadCountriesInfo() -> [(Int, String, String)] {
nameRange = nameRange1 ?? nameRange2 nameRange = nameRange1 ?? nameRange2
} }
if let nameRange = nameRange { if let nameRange = nameRange {
countryName = String(data[idRange.upperBound ..< nameRange.lowerBound]) countryName = String(data[patternRange.upperBound ..< nameRange.lowerBound])
currentLocation = nameRange.upperBound currentLocation = nameRange.upperBound
} else { } else {
countryName = String(data[idRange.upperBound ..< data.index(data.endIndex, offsetBy: -1)]) countryName = String(data[patternRange.upperBound ..< data.index(data.endIndex, offsetBy: -1)])
} }
array.append((countryCode, countryId, countryName)) array.append((countryCode, countryId, countryName))

View File

@ -73,6 +73,7 @@ public final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelega
var pending: PendingChild? var pending: PendingChild?
} }
private let isFlat: Bool
public private(set) var controllers: [ViewController] = [] public private(set) var controllers: [ViewController] = []
private var state: State = State(layout: nil, canBeClosed: nil, top: nil, transition: nil, pending: nil) private var state: State = State(layout: nil, canBeClosed: nil, top: nil, transition: nil, pending: nil)
@ -119,7 +120,8 @@ public final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelega
private var panRecognizer: InteractiveTransitionGestureRecognizer? private var panRecognizer: InteractiveTransitionGestureRecognizer?
public init(controllerRemoved: @escaping (ViewController) -> Void) { public init(isFlat: Bool, controllerRemoved: @escaping (ViewController) -> Void) {
self.isFlat = isFlat
self.controllerRemoved = controllerRemoved self.controllerRemoved = controllerRemoved
super.init() super.init()
@ -224,7 +226,7 @@ public final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelega
bottomController.viewWillAppear(true) bottomController.viewWillAppear(true)
let bottomNode = bottomController.displayNode let bottomNode = bottomController.displayNode
let navigationTransitionCoordinator = NavigationTransitionCoordinator(transition: .Pop, isInteractive: true, container: self, topNode: topNode, topNavigationBar: topController.navigationBar, bottomNode: bottomNode, bottomNavigationBar: bottomController.navigationBar, didUpdateProgress: { [weak self, weak bottomController] progress, transition, topFrame, bottomFrame in let navigationTransitionCoordinator = NavigationTransitionCoordinator(transition: .Pop, isInteractive: true, isFlat: self.isFlat, container: self, topNode: topNode, topNavigationBar: topController.navigationBar, bottomNode: bottomNode, bottomNavigationBar: bottomController.navigationBar, didUpdateProgress: { [weak self, weak bottomController] progress, transition, topFrame, bottomFrame in
if let strongSelf = self { if let strongSelf = self {
if let top = strongSelf.state.top { if let top = strongSelf.state.top {
strongSelf.syncKeyboard(leftEdge: top.value.displayNode.frame.minX, transition: transition) strongSelf.syncKeyboard(leftEdge: top.value.displayNode.frame.minX, transition: transition)
@ -459,7 +461,7 @@ public final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelega
} }
toValue.value.setIgnoreAppearanceMethodInvocations(false) toValue.value.setIgnoreAppearanceMethodInvocations(false)
let topTransition = TopTransition(type: transitionType, previous: fromValue, coordinator: NavigationTransitionCoordinator(transition: mappedTransitionType, isInteractive: false, container: self, topNode: topController.displayNode, topNavigationBar: topController.navigationBar, bottomNode: bottomController.displayNode, bottomNavigationBar: bottomController.navigationBar, didUpdateProgress: { [weak self] _, transition, topFrame, bottomFrame in let topTransition = TopTransition(type: transitionType, previous: fromValue, coordinator: NavigationTransitionCoordinator(transition: mappedTransitionType, isInteractive: false, isFlat: self.isFlat, container: self, topNode: topController.displayNode, topNavigationBar: topController.navigationBar, bottomNode: bottomController.displayNode, bottomNavigationBar: bottomController.navigationBar, didUpdateProgress: { [weak self] _, transition, topFrame, bottomFrame in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }

View File

@ -142,6 +142,7 @@ open class NavigationController: UINavigationController, ContainableController,
private let mode: NavigationControllerMode private let mode: NavigationControllerMode
private var theme: NavigationControllerTheme private var theme: NavigationControllerTheme
private let isFlat: Bool
var inCallNavigate: (() -> Void)? var inCallNavigate: (() -> Void)?
private var inCallStatusBar: StatusBar? private var inCallStatusBar: StatusBar?
@ -235,9 +236,10 @@ open class NavigationController: UINavigationController, ContainableController,
self.requestLayout(transition: transition) self.requestLayout(transition: transition)
} }
public init(mode: NavigationControllerMode, theme: NavigationControllerTheme, backgroundDetailsMode: NavigationEmptyDetailsBackgoundMode? = nil) { public init(mode: NavigationControllerMode, theme: NavigationControllerTheme, isFlat: Bool = false, backgroundDetailsMode: NavigationEmptyDetailsBackgoundMode? = nil) {
self.mode = mode self.mode = mode
self.theme = theme self.theme = theme
self.isFlat = isFlat
self.backgroundDetailsMode = backgroundDetailsMode self.backgroundDetailsMode = backgroundDetailsMode
super.init(nibName: nil, bundle: nil) super.init(nibName: nil, bundle: nil)
@ -759,7 +761,7 @@ open class NavigationController: UINavigationController, ContainableController,
transition.updateFrame(node: flatContainer, frame: CGRect(origin: CGPoint(), size: layout.size)) transition.updateFrame(node: flatContainer, frame: CGRect(origin: CGPoint(), size: layout.size))
flatContainer.update(layout: layout, canBeClosed: false, controllers: controllers, transition: transition) flatContainer.update(layout: layout, canBeClosed: false, controllers: controllers, transition: transition)
case let .split(splitContainer): case let .split(splitContainer):
let flatContainer = NavigationContainer(controllerRemoved: { [weak self] controller in let flatContainer = NavigationContainer(isFlat: self.isFlat, controllerRemoved: { [weak self] controller in
self?.controllerRemoved(controller) self?.controllerRemoved(controller)
}) })
flatContainer.statusBarStyleUpdated = { [weak self] transition in flatContainer.statusBarStyleUpdated = { [weak self] transition in
@ -782,7 +784,7 @@ open class NavigationController: UINavigationController, ContainableController,
splitContainer.removeFromSupernode() splitContainer.removeFromSupernode()
} }
} else { } else {
let flatContainer = NavigationContainer(controllerRemoved: { [weak self] controller in let flatContainer = NavigationContainer(isFlat: self.isFlat, controllerRemoved: { [weak self] controller in
self?.controllerRemoved(controller) self?.controllerRemoved(controller)
}) })
flatContainer.statusBarStyleUpdated = { [weak self] transition in flatContainer.statusBarStyleUpdated = { [weak self] transition in

View File

@ -51,7 +51,7 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
self.scrollNode = ASScrollNode() self.scrollNode = ASScrollNode()
self.container = NavigationContainer(controllerRemoved: controllerRemoved) self.container = NavigationContainer(isFlat: false, controllerRemoved: controllerRemoved)
self.container.clipsToBounds = true self.container.clipsToBounds = true
super.init() super.init()

View File

@ -51,10 +51,10 @@ final class NavigationSplitContainer: ASDisplayNode {
scrollToTop(.detail) scrollToTop(.detail)
} }
self.masterContainer = NavigationContainer(controllerRemoved: controllerRemoved) self.masterContainer = NavigationContainer(isFlat: false, controllerRemoved: controllerRemoved)
self.masterContainer.clipsToBounds = true self.masterContainer.clipsToBounds = true
self.detailContainer = NavigationContainer(controllerRemoved: controllerRemoved) self.detailContainer = NavigationContainer(isFlat: false, controllerRemoved: controllerRemoved)
self.detailContainer.clipsToBounds = true self.detailContainer.clipsToBounds = true
self.separator = ASDisplayNode() self.separator = ASDisplayNode()

View File

@ -37,6 +37,7 @@ final class NavigationTransitionCoordinator {
private let container: NavigationContainer private let container: NavigationContainer
private let transition: NavigationTransition private let transition: NavigationTransition
let isInteractive: Bool let isInteractive: Bool
let isFlat: Bool
let topNode: ASDisplayNode let topNode: ASDisplayNode
let bottomNode: ASDisplayNode let bottomNode: ASDisplayNode
private let topNavigationBar: NavigationBar? private let topNavigationBar: NavigationBar?
@ -51,9 +52,10 @@ final class NavigationTransitionCoordinator {
private var currentCompletion: (() -> Void)? private var currentCompletion: (() -> Void)?
private var didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)? private var didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)?
init(transition: NavigationTransition, isInteractive: Bool, container: NavigationContainer, topNode: ASDisplayNode, topNavigationBar: NavigationBar?, bottomNode: ASDisplayNode, bottomNavigationBar: NavigationBar?, didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)? = nil) { init(transition: NavigationTransition, isInteractive: Bool, isFlat: Bool, container: NavigationContainer, topNode: ASDisplayNode, topNavigationBar: NavigationBar?, bottomNode: ASDisplayNode, bottomNavigationBar: NavigationBar?, didUpdateProgress: ((CGFloat, ContainedViewLayoutTransition, CGRect, CGRect) -> Void)? = nil) {
self.transition = transition self.transition = transition
self.isInteractive = isInteractive self.isInteractive = isInteractive
self.isFlat = isFlat
self.container = container self.container = container
self.didUpdateProgress = didUpdateProgress self.didUpdateProgress = didUpdateProgress
self.topNode = topNode self.topNode = topNode
@ -98,8 +100,10 @@ final class NavigationTransitionCoordinator {
self.container.insertSubnode(bottomNode, belowSubnode: topNode) self.container.insertSubnode(bottomNode, belowSubnode: topNode)
} }
self.container.insertSubnode(self.dimNode, belowSubnode: topNode) if !self.isFlat {
self.container.insertSubnode(self.shadowNode, belowSubnode: self.dimNode) self.container.insertSubnode(self.dimNode, belowSubnode: topNode)
self.container.insertSubnode(self.shadowNode, belowSubnode: self.dimNode)
}
if let customTransitionNode = self.customTransitionNode { if let customTransitionNode = self.customTransitionNode {
self.container.addSubnode(customTransitionNode) self.container.addSubnode(customTransitionNode)
} }

View File

@ -203,7 +203,7 @@ public final class PhoneInputNode: ASDisplayNode, UITextFieldDelegate {
self.countryCodeField.textField.returnKeyType = .next self.countryCodeField.textField.returnKeyType = .next
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) { if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
self.countryCodeField.textField.keyboardType = .asciiCapableNumberPad self.countryCodeField.textField.keyboardType = .asciiCapableNumberPad
self.countryCodeField.textField.textContentType = .telephoneNumber // self.countryCodeField.textField.textContentType = .telephoneNumber
} else { } else {
self.countryCodeField.textField.keyboardType = .numberPad self.countryCodeField.textField.keyboardType = .numberPad
} }
@ -214,7 +214,7 @@ public final class PhoneInputNode: ASDisplayNode, UITextFieldDelegate {
self.numberField.textField.font = font self.numberField.textField.font = font
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) { if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
self.numberField.textField.keyboardType = .asciiCapableNumberPad self.numberField.textField.keyboardType = .asciiCapableNumberPad
self.numberField.textField.textContentType = .telephoneNumber // self.numberField.textField.textContentType = .telephoneNumber
} else { } else {
self.numberField.textField.keyboardType = .numberPad self.numberField.textField.keyboardType = .numberPad
} }

View File

@ -590,45 +590,14 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
strongSelf.paymentDisposable.set((inAppPurchaseManager.buyProduct(product.storeProduct, targetPeerId: strongSelf.peerId) strongSelf.paymentDisposable.set((inAppPurchaseManager.buyProduct(product.storeProduct, targetPeerId: strongSelf.peerId)
|> deliverOnMainQueue).start(next: { [weak self] status in |> deliverOnMainQueue).start(next: { [weak self] status in
if let strongSelf = self, case .purchased = status { if let strongSelf = self, case .purchased = status {
strongSelf.activationDisposable.set((strongSelf.context.account.postbox.peerView(id: strongSelf.context.account.peerId) Queue.mainQueue().after(2.0) {
|> castError(AssignAppStoreTransactionError.self) let _ = updatePremiumPromoConfigurationOnce(account: strongSelf.context.account).start()
|> take(until: { view in strongSelf.inProgress = false
if let peer = view.peers[view.peerId], peer.isPremium { strongSelf.updateInProgress(false)
return SignalTakeAction(passthrough: false, complete: true)
} else { strongSelf.updated(transition: .easeInOut(duration: 0.25))
return SignalTakeAction(passthrough: false, complete: false) strongSelf.completion(duration)
}
})
|> mapToSignal { _ -> Signal<Never, AssignAppStoreTransactionError> in
return .never()
} }
|> timeout(15.0, queue: Queue.mainQueue(), alternate: .fail(.timeout))
|> deliverOnMainQueue).start(error: { [weak self] _ in
if let strongSelf = self {
strongSelf.inProgress = false
strongSelf.updateInProgress(false)
strongSelf.updated(transition: .immediate)
// addAppLogEvent(postbox: strongSelf.context.account.postbox, type: "premium.promo_screen_fail")
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let errorText = presentationData.strings.Premium_Purchase_ErrorUnknown
let alertController = textAlertController(context: strongSelf.context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
strongSelf.present(alertController)
}
}, completed: { [weak self] in
if let strongSelf = self {
Queue.mainQueue().after(2.0) {
let _ = updatePremiumPromoConfigurationOnce(account: strongSelf.context.account).start()
strongSelf.inProgress = false
strongSelf.updateInProgress(false)
strongSelf.updated(transition: .easeInOut(duration: 0.25))
strongSelf.completion(duration)
}
}
}))
} }
}, error: { [weak self] error in }, error: { [weak self] error in
if let strongSelf = self { if let strongSelf = self {

View File

@ -61,6 +61,11 @@
@property (nonatomic, copy) void (^startMessaging)(void); @property (nonatomic, copy) void (^startMessaging)(void);
@property (nonatomic, copy) void (^startMessagingInAlternativeLanguage)(NSString *); @property (nonatomic, copy) void (^startMessagingInAlternativeLanguage)(NSString *);
@property (nonatomic, copy) UIView *(^createStartButton)(CGFloat);
- (UIView *)createAnimationSnapshot;
- (UIView *)createTextSnapshot;
@property (nonatomic) bool isEnabled; @property (nonatomic) bool isEnabled;
- (void)startTimer; - (void)startTimer;

View File

@ -24,7 +24,7 @@
_headline=headline; _headline=headline;
UILabel *headlineLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, 64+8)]; UILabel *headlineLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, 64+8)];
headlineLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:IPAD ? 96/2 : 36]; headlineLabel.font = [UIFont boldSystemFontOfSize:35.0]; //[UIFont fontWithName:@"HelveticaNeue-Light" size:IPAD ? 96/2 : 36];
headlineLabel.text = _headline; headlineLabel.text = _headline;
headlineLabel.textColor = color; headlineLabel.textColor = color;
headlineLabel.textAlignment = NSTextAlignmentCenter; headlineLabel.textAlignment = NSTextAlignmentCenter;
@ -32,14 +32,11 @@
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init]; NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
style.lineSpacing = IPAD ? 6 : 5; style.lineSpacing = IPAD ? 4 : 3;
style.lineBreakMode = NSLineBreakByWordWrapping; style.lineBreakMode = NSLineBreakByWordWrapping;
style.alignment = NSTextAlignmentCenter; style.alignment = NSTextAlignmentCenter;
NSMutableArray *boldRanges = [[NSMutableArray alloc] init]; NSMutableArray *boldRanges = [[NSMutableArray alloc] init];
NSMutableString *cleanText = [[NSMutableString alloc] initWithString:description]; NSMutableString *cleanText = [[NSMutableString alloc] initWithString:description];
@ -60,11 +57,9 @@
[boldRanges addObject:[NSValue valueWithRange:NSMakeRange(startRange.location, endRange.location - startRange.location)]]; [boldRanges addObject:[NSValue valueWithRange:NSMakeRange(startRange.location, endRange.location - startRange.location)]];
} }
_description = [[NSMutableAttributedString alloc]initWithString:cleanText]; _description = [[NSMutableAttributedString alloc]initWithString:cleanText];
NSDictionary *boldAttributes = [NSDictionary dictionaryWithObjectsAndKeys: NSDictionary *boldAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:@"HelveticaNeue-Medium" size:IPAD ? 44/2 : 17], NSFontAttributeName, nil]; [UIFont boldSystemFontOfSize:IPAD ? 22 : 17.0], NSFontAttributeName, nil];
for (NSValue *nRange in boldRanges) for (NSValue *nRange in boldRanges)
{ {
[_description addAttributes:boldAttributes range:[nRange rangeValue]]; [_description addAttributes:boldAttributes range:[nRange rangeValue]];
@ -76,7 +71,7 @@
[_description addAttribute:NSForegroundColorAttributeName value:color range:NSMakeRange(0, _description.length)]; [_description addAttribute:NSForegroundColorAttributeName value:color range:NSMakeRange(0, _description.length)];
UILabel *descriptionLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 25 + (IPAD ? 22 : 0), frame.size.width, 120+8+5)]; UILabel *descriptionLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 25 + (IPAD ? 22 : 0), frame.size.width, 120+8+5)];
descriptionLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:IPAD ? 44/2 : 17]; descriptionLabel.font = [UIFont systemFontOfSize:IPAD ? 22 : 17.0];
descriptionLabel.attributedText = _description; descriptionLabel.attributedText = _description;
descriptionLabel.numberOfLines=0; descriptionLabel.numberOfLines=0;
descriptionLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth; descriptionLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;

View File

@ -93,7 +93,6 @@ typedef enum {
UIColor *_regularDotColor; UIColor *_regularDotColor;
UIColor *_highlightedDotColor; UIColor *_highlightedDotColor;
UIButton *_startButton;
TGModernButton *_alternativeLanguageButton; TGModernButton *_alternativeLanguageButton;
SMetaDisposable *_localizationsDisposable; SMetaDisposable *_localizationsDisposable;
@ -102,6 +101,8 @@ typedef enum {
SVariable *_alternativeLocalization; SVariable *_alternativeLocalization;
NSDictionary<NSString *, NSString *> *_englishStrings; NSDictionary<NSString *, NSString *> *_englishStrings;
UIView *_wrapperView;
bool _loadedView; bool _loadedView;
} }
@end @end
@ -308,6 +309,9 @@ typedef enum {
[self loadGL]; [self loadGL];
_wrapperView = [[UIScrollView alloc]initWithFrame:self.view.bounds];
[self.view addSubview:_wrapperView];
_pageScrollView = [[UIScrollView alloc]initWithFrame:self.view.bounds]; _pageScrollView = [[UIScrollView alloc]initWithFrame:self.view.bounds];
_pageScrollView.clipsToBounds = true; _pageScrollView.clipsToBounds = true;
_pageScrollView.opaque = true; _pageScrollView.opaque = true;
@ -317,7 +321,7 @@ typedef enum {
_pageScrollView.pagingEnabled = true; _pageScrollView.pagingEnabled = true;
_pageScrollView.contentSize = CGSizeMake(_headlines.count * self.view.bounds.size.width, self.view.bounds.size.height); _pageScrollView.contentSize = CGSizeMake(_headlines.count * self.view.bounds.size.width, self.view.bounds.size.height);
_pageScrollView.delegate = self; _pageScrollView.delegate = self;
[self.view addSubview:_pageScrollView]; [_wrapperView addSubview:_pageScrollView];
_pageViews = [NSMutableArray array]; _pageViews = [NSMutableArray array];
@ -331,41 +335,6 @@ typedef enum {
} }
[_pageScrollView setPage:0]; [_pageScrollView setPage:0];
_startButton = [[UIButton alloc] init];
_startButton.adjustsImageWhenDisabled = false;
[_startButton setTitle:_englishStrings[@"Tour.StartButton"] forState:UIControlStateNormal];
[_startButton.titleLabel setFont:TGMediumSystemFontOfSize(20.0f)];
[_startButton setTitleColor:_backgroundColor forState:UIControlStateNormal];
static UIImage *buttonBackgroundImage = nil;
static UIImage *buttonHighlightedBackgroundImage = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
{
UIGraphicsBeginImageContextWithOptions(CGSizeMake(48.0, 48.0), false, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [_buttonColor CGColor]);
CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, 48.0f, 48.0f));
buttonBackgroundImage = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:24 topCapHeight:24];
UIGraphicsEndImageContext();
}
{
UIGraphicsBeginImageContextWithOptions(CGSizeMake(48.0, 48.0), false, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
CGFloat hue = 0.0f;
CGFloat sat = 0.0f;
CGFloat bri = 0.0f;
[_buttonColor getHue:&hue saturation:&sat brightness:&bri alpha:nil];
UIColor *color = [[UIColor alloc] initWithHue:hue saturation:sat brightness:bri * 0.7 alpha:1.0];
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillEllipseInRect(context, CGRectMake(0.0f, 0.0f, 48.0f, 48.0f));
buttonHighlightedBackgroundImage = [UIGraphicsGetImageFromCurrentImageContext() stretchableImageWithLeftCapWidth:24 topCapHeight:24];
UIGraphicsEndImageContext();
}
});
[_startButton setContentEdgeInsets:UIEdgeInsetsMake(0.0f, 20.0f, 0.0f, 20.0f)];
[_startButton setBackgroundImage:buttonBackgroundImage forState:UIControlStateNormal];
[_startButton setBackgroundImage:buttonHighlightedBackgroundImage forState:UIControlStateHighlighted];
[self.view addSubview:_startButton];
[self.view addSubview:_alternativeLanguageButton]; [self.view addSubview:_alternativeLanguageButton];
_pageControl = [[UIPageControl alloc] init]; _pageControl = [[UIPageControl alloc] init];
@ -374,7 +343,20 @@ typedef enum {
[_pageControl setNumberOfPages:6]; [_pageControl setNumberOfPages:6];
_pageControl.pageIndicatorTintColor = _regularDotColor; _pageControl.pageIndicatorTintColor = _regularDotColor;
_pageControl.currentPageIndicatorTintColor = _highlightedDotColor; _pageControl.currentPageIndicatorTintColor = _highlightedDotColor;
[self.view addSubview:_pageControl]; [_wrapperView addSubview:_pageControl];
}
- (UIView *)createAnimationSnapshot {
UIImage *image = _glkView.snapshot;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:_glkView.frame];
imageView.image = image;
return imageView;
}
- (UIView *)createTextSnapshot {
UIView *snapshotView = [_wrapperView snapshotViewAfterScreenUpdates:false];
snapshotView.frame = _wrapperView.frame;
return snapshotView;
} }
- (BOOL)shouldAutorotate - (BOOL)shouldAutorotate
@ -527,12 +509,16 @@ typedef enum {
_pageControl.frame = CGRectMake(0, pageControlY, self.view.bounds.size.width, 7); _pageControl.frame = CGRectMake(0, pageControlY, self.view.bounds.size.width, 7);
_glkView.frame = CGRectChangedOriginY(_glkView.frame, glViewY - statusBarHeight); _glkView.frame = CGRectChangedOriginY(_glkView.frame, glViewY - statusBarHeight);
[_startButton sizeToFit]; CGFloat startButtonWidth = self.view.bounds.size.width - 48.0f;
_startButton.frame = CGRectMake(floor((self.view.bounds.size.width - _startButton.frame.size.width) / 2.0f), self.view.bounds.size.height - startButtonY - statusBarHeight, _startButton.frame.size.width, 48.0f); UIView *startButton = self.createStartButton(startButtonWidth);
[_startButton addTarget:self action:@selector(startButtonPress) forControlEvents:UIControlEventTouchUpInside]; if (startButton.superview == nil) {
[self.view addSubview:startButton];
}
startButton.frame = CGRectMake(floor((self.view.bounds.size.width - startButtonWidth) / 2.0f), self.view.bounds.size.height - startButtonY - statusBarHeight, startButtonWidth, 50.0f);
_alternativeLanguageButton.frame = CGRectMake(floor((self.view.bounds.size.width - _alternativeLanguageButton.frame.size.width) / 2.0f), CGRectGetMaxY(_startButton.frame) + languageButtonOffset, _alternativeLanguageButton.frame.size.width, _alternativeLanguageButton.frame.size.height); _alternativeLanguageButton.frame = CGRectMake(floor((self.view.bounds.size.width - _alternativeLanguageButton.frame.size.width) / 2.0f), CGRectGetMaxY(startButton.frame) + languageButtonOffset, _alternativeLanguageButton.frame.size.width, _alternativeLanguageButton.frame.size.height);
_wrapperView.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);
_pageScrollView.frame=CGRectMake(0, 20, self.view.bounds.size.width, self.view.bounds.size.height - 20); _pageScrollView.frame=CGRectMake(0, 20, self.view.bounds.size.width, self.view.bounds.size.height - 20);
_pageScrollView.contentSize=CGSizeMake(_headlines.count * self.view.bounds.size.width, 150); _pageScrollView.contentSize=CGSizeMake(_headlines.count * self.view.bounds.size.width, 150);
_pageScrollView.contentOffset = CGPointMake(_currentPage * self.view.bounds.size.width, 0); _pageScrollView.contentOffset = CGPointMake(_currentPage * self.view.bounds.size.width, 0);
@ -691,7 +677,6 @@ NSInteger _current_page_end;
- (void)setIsEnabled:(bool)isEnabled { - (void)setIsEnabled:(bool)isEnabled {
if (_isEnabled != isEnabled) { if (_isEnabled != isEnabled) {
_isEnabled = isEnabled; _isEnabled = isEnabled;
_startButton.alpha = _isEnabled ? 1.0 : 0.6;
_alternativeLanguageButton.alpha = _isEnabled ? 1.0 : 0.6; _alternativeLanguageButton.alpha = _isEnabled ? 1.0 : 0.6;
} }
} }

View File

@ -137,11 +137,11 @@ private struct ChangePhoneNumberCodeControllerState: Equatable {
} }
} }
private func changePhoneNumberCodeControllerEntries(presentationData: PresentationData, state: ChangePhoneNumberCodeControllerState, codeData: ChangeAccountPhoneNumberData, timeout: Int32?, strings: PresentationStrings) -> [ChangePhoneNumberCodeEntry] { private func changePhoneNumberCodeControllerEntries(presentationData: PresentationData, state: ChangePhoneNumberCodeControllerState, codeData: ChangeAccountPhoneNumberData, timeout: Int32?, strings: PresentationStrings, phoneNumber: String) -> [ChangePhoneNumberCodeEntry] {
var entries: [ChangePhoneNumberCodeEntry] = [] var entries: [ChangePhoneNumberCodeEntry] = []
entries.append(.codeEntry(presentationData.theme, presentationData.strings, presentationData.strings.ChangePhoneNumberCode_CodePlaceholder, state.codeText)) entries.append(.codeEntry(presentationData.theme, presentationData.strings, presentationData.strings.ChangePhoneNumberCode_CodePlaceholder, state.codeText))
var text = authorizationCurrentOptionText(codeData.type, strings: presentationData.strings, primaryColor: presentationData.theme.list.itemPrimaryTextColor, accentColor: presentationData.theme.list.itemAccentColor).string var text = authorizationCurrentOptionText(codeData.type, phoneNumber: phoneNumber, email: nil, strings: presentationData.strings, primaryColor: presentationData.theme.list.itemPrimaryTextColor, accentColor: presentationData.theme.list.itemAccentColor).string
if let nextType = codeData.nextType { if let nextType = codeData.nextType {
text += "\n\n" + authorizationNextOptionText(currentType: codeData.type, nextType: nextType, timeout: timeout, strings: presentationData.strings, primaryColor: .black, accentColor: .black).0.string text += "\n\n" + authorizationNextOptionText(currentType: codeData.type, nextType: nextType, timeout: timeout, strings: presentationData.strings, primaryColor: .black, accentColor: .black).0.string
} }
@ -316,7 +316,7 @@ func changePhoneNumberCodeController(context: AccountContext, phoneNumber: Strin
} }
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(formatPhoneNumber(phoneNumber)), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(formatPhoneNumber(phoneNumber)), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: changePhoneNumberCodeControllerEntries(presentationData: presentationData, state: state, codeData: data, timeout: timeout, strings: presentationData.strings), style: .blocks, focusItemTag: ChangePhoneNumberCodeTag.input, emptyStateItem: nil, animateChanges: false) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: changePhoneNumberCodeControllerEntries(presentationData: presentationData, state: state, codeData: data, timeout: timeout, strings: presentationData.strings, phoneNumber: phoneNumber), style: .blocks, focusItemTag: ChangePhoneNumberCodeTag.input, emptyStateItem: nil, animateChanges: false)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} |> afterDisposed { } |> afterDisposed {

View File

@ -263,7 +263,7 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
self.setupGloss() self.setupGloss()
} }
private func setupGloss() { private func setupGloss() {
if self.gloss { if self.gloss {
if self.shimmerView == nil { if self.shimmerView == nil {
@ -312,6 +312,39 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
} }
} }
public func animateTitle(from title: String) {
let originalTitle = self.title ?? ""
self.title = title
Queue.mainQueue().justDispatch {
if let snapshotView = self.titleNode.view.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = self.titleNode.frame
self.view.insertSubview(snapshotView, aboveSubview: self.titleNode.view)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
})
self.titleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.title = originalTitle
}
}
}
public func animateTitle(to title: String) {
if let snapshotView = self.titleNode.view.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = self.titleNode.frame
self.view.insertSubview(snapshotView, aboveSubview: self.titleNode.view)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
})
self.titleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.title = title
}
}
private func setupGradientAnimations() { private func setupGradientAnimations() {
guard let buttonBackgroundAnimationView = self.buttonBackgroundAnimationView else { guard let buttonBackgroundAnimationView = self.buttonBackgroundAnimationView else {
return return

View File

@ -1,232 +1,235 @@
1876;JM;Jamaica 376;AD;XX XX XX;Andorra
1869;KN;Saint Kitts & Nevis 971;AE;XX XXX XXXX;United Arab Emirates
1868;TT;Trinidad & Tobago 93;AF;XXX XXX XXX;Afghanistan
1784;VC;Saint Vincent & the Grenadines 1268;AG;XXX XXXX;Antigua & Barbuda
1767;DM;Dominica 1264;AI;XXX XXXX;Anguilla
1758;LC;Saint Lucia 355;AL;XX XXX XXXX;Albania
1721;SX;Sint Maarten 374;AM;XX XXX XXX;Armenia
1684;AS;American Samoa 244;AO;XXX XXX XXX;Angola
1671;GU;Guam 54;AR;;Argentina
1670;MP;Northern Mariana Islands 1684;AS;XXX XXXX;American Samoa
1664;MS;Montserrat 43;AT;XXX XXXXXX;Austria
1649;TC;Turks & Caicos Islands 61;AU;X XXXX XXXX;Australia
1473;GD;Grenada 297;AW;XXX XXXX;Aruba
1441;BM;Bermuda 994;AZ;XX XXX XXXX;Azerbaijan
1345;KY;Cayman Islands 387;BA;XX XXX XXX;Bosnia & Herzegovina
1340;VI;US Virgin Islands 1246;BB;XXX XXXX;Barbados
1284;VG;British Virgin Islands 880;BD;XX XXX XXX;Bangladesh
1268;AG;Antigua & Barbuda 32;BE;XXX XX XX XX;Belgium
1264;AI;Anguilla 226;BF;XX XX XX XX;Burkina Faso
1246;BB;Barbados 359;BG;;Bulgaria
1242;BS;Bahamas 973;BH;XXXX XXXX;Bahrain
998;UZ;Uzbekistan 257;BI;XX XX XXXX;Burundi
996;KG;Kyrgyzstan 229;BJ;XX XXX XXX;Benin
995;GE;Georgia 1441;BM;XXX XXXX;Bermuda
994;AZ;Azerbaijan 673;BN;XXX XXXX;Brunei Darussalam
993;TM;Turkmenistan 591;BO;X XXX XXXX;Bolivia
992;TJ;Tajikistan 599;BQ;;Bonaire, Sint Eustatius & Saba
977;NP;Nepal 55;BR;XX XXXXX XXXX;Brazil
976;MN;Mongolia 1242;BS;XXX XXXX;Bahamas
975;BT;Bhutan 975;BT;XX XXX XXX;Bhutan
974;QA;Qatar 267;BW;XX XXX XXX;Botswana
973;BH;Bahrain 375;BY;XX XXX XXXX;Belarus
972;IL;Israel 501;BZ;;Belize
971;AE;United Arab Emirates 1;US;XXX XXX XXXX;United States
970;PS;Palestine 1;CA;XXX XXX XXXX;Canada
968;OM;Oman 243;CD;XX XXX XXXX;Congo (Dem. Rep.)
967;YE;Yemen 236;CF;XX XX XX XX;Central African Rep.
966;SA;Saudi Arabia 242;CG;XX XXX XXXX;Congo (Rep.)
965;KW;Kuwait 41;CH;XX XXX XXXX;Switzerland
964;IQ;Iraq 225;CI;XX XX XX XXXX;Côte d'Ivoire
963;SY;Syrian Arab Republic 682;CK;;Cook Islands
962;JO;Jordan 56;CL;X XXXX XXXX;Chile
961;LB;Lebanon 237;CM;XXXX XXXX;Cameroon
960;MV;Maldives 86;CN;XXX XXXX XXXX;China
886;TW;Taiwan 57;CO;XXX XXX XXXX;Colombia
880;BD;Bangladesh 506;CR;XXXX XXXX;Costa Rica
856;LA;Laos 53;CU;X XXX XXXX;Cuba
855;KH;Cambodia 238;CV;XXX XXXX;Cape Verde
853;MO;Macau 599;CW;;Curaçao
852;HK;Hong Kong 357;CY;XXXX XXXX;Cyprus
850;KP;North Korea 420;CZ;XXX XXX XXX;Czech Republic
692;MH;Marshall Islands 49;DE;;Germany
691;FM;Micronesia 253;DJ;XX XX XX XX;Djibouti
690;TK;Tokelau 45;DK;XXXX XXXX;Denmark
689;PF;French Polynesia 1767;DM;XXX XXXX;Dominica
688;TV;Tuvalu 1809;DO;XXX XXXX;Dominican Rep.
687;NC;New Caledonia 1829;DO;XXX XXXX;Dominican Rep.
686;KI;Kiribati 1849;DO;XXX XXXX;Dominican Rep.
685;WS;Samoa 213;DZ;XXX XX XX XX;Algeria
683;NU;Niue 593;EC;XX XXX XXXX;Ecuador
682;CK;Cook Islands 372;EE;XXXX XXX;Estonia
681;WF;Wallis & Futuna 20;EG;XX XXXX XXXX;Egypt
680;PW;Palau 291;ER;X XXX XXX;Eritrea
679;FJ;Fiji 34;ES;XXX XXX XXX;Spain
678;VU;Vanuatu 251;ET;XX XXX XXX;Ethiopia
677;SB;Solomon Islands 358;FI;;Finland
676;TO;Tonga 679;FJ;XXX XXXX;Fiji
675;PG;Papua New Guinea 500;FK;;Falkland Islands
674;NR;Nauru 691;FM;;Micronesia
673;BN;Brunei Darussalam 298;FO;XXX XXX;Faroe Islands
672;NF;Norfolk Island 33;FR;X XX XX XX XX;France
670;TL;Timor-Leste 241;GA;X XX XX XX;Gabon
599;BQ;Bonaire, Sint Eustatius & Saba 44;GB;XXXX XXXXXX;United Kingdom
599;CW;Curaçao 1473;GD;XXX XXXX;Grenada
598;UY;Uruguay 995;GE;XXX XXX XXX;Georgia
597;SR;Suriname 594;GF;;French Guiana
596;MQ;Martinique 233;GH;XX XXX XXXX;Ghana
595;PY;Paraguay 350;GI;XXXX XXXX;Gibraltar
594;GF;French Guiana 299;GL;XXX XXX;Greenland
593;EC;Ecuador 220;GM;XXX XXXX;Gambia
592;GY;Guyana 224;GN;XXX XXX XXX;Guinea
591;BO;Bolivia 590;GP;XXX XX XX XX;Guadeloupe
590;GP;Guadeloupe 240;GQ;XXX XXX XXX;Equatorial Guinea
509;HT;Haiti 30;GR;XXX XXX XXXX;Greece
508;PM;Saint Pierre & Miquelon 502;GT;X XXX XXXX;Guatemala
507;PA;Panama 1671;GU;XXX XXXX;Guam
506;CR;Costa Rica 245;GW;XXX XXXX;Guinea-Bissau
505;NI;Nicaragua 592;GY;;Guyana
504;HN;Honduras 852;HK;X XXX XXXX;Hong Kong
503;SV;El Salvador 504;HN;XXXX XXXX;Honduras
502;GT;Guatemala 385;HR;XX XXX XXX;Croatia
501;BZ;Belize 509;HT;XXXX XXXX;Haiti
500;FK;Falkland Islands 36;HU;XXX XXX XXX;Hungary
423;LI;Liechtenstein 62;ID;XXX XXXXXX;Indonesia
421;SK;Slovakia 353;IE;XX XXX XXXX;Ireland
420;CZ;Czech Republic 972;IL;XX XXX XXXX;Israel
383;XK;Kosovo 91;IN;XXXXX XXXXX;India
389;MK;Macedonia 246;IO;XXX XXXX;Diego Garcia
387;BA;Bosnia & Herzegovina 964;IQ;XXX XXX XXXX;Iraq
386;SI;Slovenia 98;IR;XXX XXX XXXX;Iran
385;HR;Croatia 354;IS;XXX XXXX;Iceland
382;ME;Montenegro 39;IT;XXX XXX XXXX;Italy
381;RS;Serbia 1876;JM;XXX XXXX;Jamaica
380;UA;Ukraine 962;JO;X XXXX XXXX;Jordan
378;SM;San Marino 81;JP;XX XXXX XXXX;Japan
377;MC;Monaco 254;KE;XXX XXX XXX;Kenya
376;AD;Andorra 996;KG;XXX XXXXXX;Kyrgyzstan
375;BY;Belarus 855;KH;XX XXX XXX;Cambodia
374;AM;Armenia 686;KI;XXXX XXXX;Kiribati
373;MD;Moldova 269;KM;XXX XXXX;Comoros
372;EE;Estonia 1869;KN;XXX XXXX;Saint Kitts & Nevis
371;LV;Latvia 850;KP;;North Korea
370;LT;Lithuania 82;KR;XX XXXX XXX;South Korea
359;BG;Bulgaria 965;KW;XXXX XXXX;Kuwait
358;FI;Finland 1345;KY;XXX XXXX;Cayman Islands
357;CY;Cyprus 7;RU;XXX XXX XXXX;Russian Federation
356;MT;Malta 7;KZ;XXX XXX XX XX;Kazakhstan
355;AL;Albania 856;LA;XX XX XXX XXX;Laos
354;IS;Iceland 961;LB;;Lebanon
353;IE;Ireland 1758;LC;XXX XXXX;Saint Lucia
352;LU;Luxembourg 423;LI;XXX XXXX;Liechtenstein
351;PT;Portugal 94;LK;XX XXX XXXX;Sri Lanka
350;GI;Gibraltar 231;LR;XX XXX XXXX;Liberia
299;GL;Greenland 266;LS;XX XXX XXX;Lesotho
298;FO;Faroe Islands 370;LT;XXX XXXXX;Lithuania
297;AW;Aruba 352;LU;XXX XXX XXX;Luxembourg
291;ER;Eritrea 371;LV;XXX XXXXX;Latvia
290;SH;Saint Helena 218;LY;XX XXX XXXX;Libya
269;KM;Comoros 212;MA;XX XXX XXXX;Morocco
268;SZ;Swaziland 377;MC;XXXX XXXX;Monaco
267;BW;Botswana 373;MD;XX XXX XXX;Moldova
266;LS;Lesotho 382;ME;;Montenegro
265;MW;Malawi 261;MG;XX XX XXX XX;Madagascar
264;NA;Namibia 692;MH;;Marshall Islands
263;ZW;Zimbabwe 389;MK;XX XXXXXX;North Macedonia
262;RE;Réunion 223;ML;XXXX XXXX;Mali
261;MG;Madagascar 95;MM;;Myanmar
260;ZM;Zambia 976;MN;XX XX XXXX;Mongolia
258;MZ;Mozambique 853;MO;XXXX XXXX;Macau
257;BI;Burundi 1670;MP;XXX XXXX;Northern Mariana Islands
256;UG;Uganda 596;MQ;;Martinique
255;TZ;Tanzania 222;MR;XXXX XXXX;Mauritania
254;KE;Kenya 1664;MS;XXX XXXX;Montserrat
253;DJ;Djibouti 356;MT;XX XX XX XX;Malta
252;SO;Somalia 230;MU;XXXX XXXX;Mauritius
251;ET;Ethiopia 960;MV;XXX XXXX;Maldives
250;RW;Rwanda 265;MW;XX XXX XXXX;Malawi
249;SD;Sudan 52;MX;;Mexico
248;SC;Seychelles 60;MY;;Malaysia
247;SH;Saint Helena 258;MZ;XX XXX XXXX;Mozambique
246;IO;Diego Garcia 264;NA;XX XXX XXXX;Namibia
245;GW;Guinea-Bissau 687;NC;;New Caledonia
244;AO;Angola 227;NE;XX XX XX XX;Niger
243;CD;Congo (Dem. Rep.) 672;NF;;Norfolk Island
242;CG;Congo (Rep.) 234;NG;XX XXXX XXXX;Nigeria
241;GA;Gabon 505;NI;XXXX XXXX;Nicaragua
240;GQ;Equatorial Guinea 31;NL;X XX XX XX XX;Netherlands
239;ST;São Tomé & Príncipe 47;NO;XXX XX XXX;Norway
238;CV;Cape Verde 977;NP;XX XXXX XXXX;Nepal
237;CM;Cameroon 674;NR;;Nauru
236;CF;Central African Rep. 683;NU;;Niue
235;TD;Chad 64;NZ;XXXX XXXX;New Zealand
234;NG;Nigeria 968;OM;XXXX XXXX;Oman
233;GH;Ghana 507;PA;XXXX XXXX;Panama
232;SL;Sierra Leone 51;PE;XXX XXX XXX;Peru
231;LR;Liberia 689;PF;;French Polynesia
230;MU;Mauritius 675;PG;;Papua New Guinea
229;BJ;Benin 63;PH;XXX XXX XXXX;Philippines
228;TG;Togo 92;PK;XXX XXX XXXX;Pakistan
227;NE;Niger 48;PL;XXX XXX XXX;Poland
226;BF;Burkina Faso 508;PM;;Saint Pierre & Miquelon
225;CI;Côte d`Ivoire 1787;PR;XXX XXXX;Puerto Rico
224;GN;Guinea 1939;PR;XXX XXXX;Puerto Rico
223;ML;Mali 970;PS;XXX XX XXXX;Palestine
222;MR;Mauritania 351;PT;XXX XXX XXX;Portugal
221;SN;Senegal 680;PW;;Palau
220;GM;Gambia 595;PY;XXX XXX XXX;Paraguay
218;LY;Libya 974;QA;XX XXX XXX;Qatar
216;TN;Tunisia 262;RE;XXX XXX XXX;Réunion
213;DZ;Algeria 40;RO;XXX XXX XXX;Romania
212;MA;Morocco 381;RS;XX XXX XXX;Serbia
211;SS;South Sudan 250;RW;XXX XXX XXX;Rwanda
98;IR;Iran 966;SA;XX XXX XXXX;Saudi Arabia
95;MM;Myanmar 677;SB;;Solomon Islands
94;LK;Sri Lanka 248;SC;X XX XX XX;Seychelles
93;AF;Afghanistan 249;SD;XX XXX XXXX;Sudan
92;PK;Pakistan 46;SE;XX XXX XXXX;Sweden
91;IN;India 65;SG;XXXX XXXX;Singapore
90;TR;Turkey 247;SH;;Saint Helena
86;CN;China 290;SH;XX XXX;Saint Helena
84;VN;Vietnam 386;SI;XX XXX XXX;Slovenia
82;KR;South Korea 421;SK;XXX XXX XXX;Slovakia
81;JP;Japan 232;SL;XX XXX XXX;Sierra Leone
66;TH;Thailand 378;SM;;San Marino
65;SG;Singapore 221;SN;XX XXX XXXX;Senegal
64;NZ;New Zealand 252;SO;XX XXX XXX;Somalia
63;PH;Philippines 597;SR;XXX XXXX;Suriname
62;ID;Indonesia 211;SS;XX XXX XXXX;South Sudan
61;AU;Australia 239;ST;XX XXXXX;São Tomé & Príncipe
60;MY;Malaysia 503;SV;XXXX XXXX;El Salvador
58;VE;Venezuela 1721;SX;XXX XXXX;Sint Maarten
57;CO;Colombia 963;SY;XXX XXX XXX;Syria
56;CL;Chile 268;SZ;XXXX XXXX;Eswatini
55;BR;Brazil 1649;TC;XXX XXXX;Turks & Caicos Islands
54;AR;Argentina 235;TD;XX XX XX XX;Chad
53;CU;Cuba 228;TG;XX XXX XXX;Togo
52;MX;Mexico 66;TH;X XXXX XXXX;Thailand
51;PE;Peru 992;TJ;XX XXX XXXX;Tajikistan
49;DE;Germany 690;TK;;Tokelau
48;PL;Poland 670;TL;;Timor-Leste
47;NO;Norway 993;TM;XX XXXXXX;Turkmenistan
46;SE;Sweden 216;TN;XX XXX XXX;Tunisia
45;DK;Denmark 676;TO;;Tonga
44;GB;United Kingdom 90;TR;XXX XXX XXXX;Turkey
43;AT;Austria 1868;TT;XXX XXXX;Trinidad & Tobago
41;CH;Switzerland 688;TV;;Tuvalu
40;RO;Romania 886;TW;XXX XXX XXX;Taiwan
39;IT;Italy 255;TZ;XX XXX XXXX;Tanzania
36;HU;Hungary 380;UA;XX XXX XX XX;Ukraine
34;ES;Spain 256;UG;XX XXX XXXX;Uganda
33;FR;France 598;UY;X XXX XXXX;Uruguay
32;BE;Belgium 998;UZ;XX XXX XX XX;Uzbekistan
31;NL;Netherlands 1784;VC;XXX XXXX;Saint Vincent & the Grenadines
30;GR;Greece 58;VE;XXX XXX XXXX;Venezuela
27;ZA;South Africa 1284;VG;XXX XXXX;British Virgin Islands
20;EG;Egypt 1340;VI;XXX XXXX;US Virgin Islands
7;RU;Russian Federation 84;VN;;Vietnam
7;KZ;Kazakhstan 678;VU;;Vanuatu
1;US;USA 681;WF;;Wallis & Futuna
1;PR;Puerto Rico 685;WS;;Samoa
1;DO;Dominican Rep. 383;XK;XXXX XXXX;Kosovo
1;CA;Canada 967;YE;XXX XXX XXX;Yemen
27;ZA;XX XXX XXXX;South Africa
260;ZM;XX XXX XXXX;Zambia
263;ZW;XX XXX XXXX;Zimbabwe

View File

@ -1105,8 +1105,10 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|> take(1) |> take(1)
|> timeout(4.0, queue: .mainQueue(), alternate: .complete()) |> timeout(4.0, queue: .mainQueue(), alternate: .complete())
|> deliverOnMainQueue).start(completed: { |> deliverOnMainQueue).start(completed: {
authContextValue.rootController.view.endEditing(true) Queue.mainQueue().after(0.75) {
authContextValue.rootController.dismiss() authContextValue.rootController.view.endEditing(true)
authContextValue.rootController.dismiss()
}
}) })
} else { } else {
authContextValue.rootController.view.endEditing(true) authContextValue.rootController.view.endEditing(true)

View File

@ -115,6 +115,15 @@ final class AuthorizationSequenceCodeEntryController: ViewController {
self.controllerNode.resetCode() self.controllerNode.resetCode()
} }
func animateSuccess() {
self.controllerNode.animateSuccess()
}
func animateError(text: String) {
self.hapticFeedback.error()
self.controllerNode.animateError(text: text)
}
func updateData(number: String, codeType: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, timeout: Int32?, termsOfService: (UnauthorizedAccountTermsOfService, Bool)?) { func updateData(number: String, codeType: SentAuthorizationCodeType, nextType: AuthorizationCodeNextType?, timeout: Int32?, termsOfService: (UnauthorizedAccountTermsOfService, Bool)?) {
self.termsOfService = termsOfService self.termsOfService = termsOfService
if self.data?.0 != number || self.data?.1 != codeType || self.data?.2 != nextType || self.data?.3 != timeout { if self.data?.0 != number || self.data?.1 != codeType || self.data?.2 != nextType || self.data?.3 != timeout {

View File

@ -33,6 +33,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
private var signInWithAppleButton: UIControl? private var signInWithAppleButton: UIControl?
private let codeInputView: CodeInputView private let codeInputView: CodeInputView
private let errorTextNode: ImmediateTextNode
private var codeType: SentAuthorizationCodeType? private var codeType: SentAuthorizationCodeType?
@ -69,7 +70,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
self.codeInputView.alpha = self.inProgress ? 0.6 : 1.0 self.codeInputView.alpha = self.inProgress ? 0.6 : 1.0
} }
} }
init(strings: PresentationStrings, theme: PresentationTheme) { init(strings: PresentationStrings, theme: PresentationTheme) {
self.strings = strings self.strings = strings
self.theme = theme self.theme = theme
@ -119,6 +120,11 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
self.codeInputView.textField.keyboardType = .numberPad self.codeInputView.textField.keyboardType = .numberPad
} }
self.errorTextNode = ImmediateTextNode()
self.errorTextNode.alpha = 0.0
self.errorTextNode.displaysAsynchronously = false
self.errorTextNode.textAlignment = .center
self.dividerNode = AuthorizationDividerNode(theme: self.theme, strings: self.strings) self.dividerNode = AuthorizationDividerNode(theme: self.theme, strings: self.strings)
if #available(iOS 13.0, *) { if #available(iOS 13.0, *) {
@ -136,8 +142,6 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
self.backgroundColor = self.theme.list.plainBackgroundColor self.backgroundColor = self.theme.list.plainBackgroundColor
self.addSubnode(self.codeInputView) self.addSubnode(self.codeInputView)
//self.addSubnode(self.codeSeparatorNode)
//self.addSubnode(self.codeField)
self.addSubnode(self.titleNode) self.addSubnode(self.titleNode)
self.addSubnode(self.titleIconNode) self.addSubnode(self.titleIconNode)
self.addSubnode(self.currentOptionNode) self.addSubnode(self.currentOptionNode)
@ -145,6 +149,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
self.addSubnode(self.nextOptionButtonNode) self.addSubnode(self.nextOptionButtonNode)
self.addSubnode(self.animationNode) self.addSubnode(self.animationNode)
self.addSubnode(self.dividerNode) self.addSubnode(self.dividerNode)
self.addSubnode(self.errorTextNode)
self.codeInputView.updated = { [weak self] in self.codeInputView.updated = { [weak self] in
guard let strongSelf = self else { guard let strongSelf = self else {
@ -208,7 +213,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
} }
self.appleSignInAllowed = appleSignInAllowed self.appleSignInAllowed = appleSignInAllowed
self.currentOptionNode.attributedText = authorizationCurrentOptionText(codeType, strings: self.strings, primaryColor: self.theme.list.itemPrimaryTextColor, accentColor: self.theme.list.itemAccentColor) self.currentOptionNode.attributedText = authorizationCurrentOptionText(codeType, phoneNumber: self.phoneNumber, email: nil, strings: self.strings, primaryColor: self.theme.list.itemPrimaryTextColor, accentColor: self.theme.list.itemAccentColor)
if case .missedCall = codeType { if case .missedCall = codeType {
self.currentOptionInfoNode.attributedText = NSAttributedString(string: self.strings.Login_CodePhonePatternInfoText, font: Font.regular(17.0), textColor: self.theme.list.itemPrimaryTextColor, paragraphAlignment: .center) self.currentOptionInfoNode.attributedText = NSAttributedString(string: self.strings.Login_CodePhonePatternInfoText, font: Font.regular(17.0), textColor: self.theme.list.itemPrimaryTextColor, paragraphAlignment: .center)
} else { } else {
@ -259,18 +264,18 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
var animationName = "IntroMessage" var animationName = "IntroMessage"
if let codeType = self.codeType { if let codeType = self.codeType {
switch codeType { switch codeType {
case .otherSession:
self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_CheckOtherSessionMessages, font: Font.semibold(28.0), textColor: self.theme.list.itemPrimaryTextColor)
case .missedCall: case .missedCall:
self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_EnterMissingDigits, font: Font.semibold(28.0), textColor: self.theme.list.itemPrimaryTextColor) self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_EnterMissingDigits, font: Font.semibold(28.0), textColor: self.theme.list.itemPrimaryTextColor)
case .email: case .email:
self.titleNode.attributedText = NSAttributedString(string: "Check Your Email", font: Font.semibold(28.0), textColor: self.theme.list.itemPrimaryTextColor) self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_EnterCodeEmailTitle, font: Font.semibold(28.0), textColor: self.theme.list.itemPrimaryTextColor)
animationName = "IntroLetter" animationName = "IntroLetter"
case .sms:
self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_EnterCodeSMSTitle, font: Font.semibold(28.0), textColor: self.theme.list.itemPrimaryTextColor)
default: default:
self.titleNode.attributedText = NSAttributedString(string: self.phoneNumber, font: Font.semibold(28.0), textColor: self.theme.list.itemPrimaryTextColor) self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_EnterCodeTelegramTitle, font: Font.semibold(28.0), textColor: self.theme.list.itemPrimaryTextColor)
} }
} else { } else {
self.titleNode.attributedText = NSAttributedString(string: self.phoneNumber, font: Font.semibold(40.0), textColor: self.theme.list.itemPrimaryTextColor) self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_EnterCodeTelegramTitle, font: Font.semibold(40.0), textColor: self.theme.list.itemPrimaryTextColor)
} }
if let inputHeight = layout.inputHeight { if let inputHeight = layout.inputHeight {
@ -286,11 +291,11 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
self.animationNode.visibility = true self.animationNode.visibility = true
} }
let animationSize = CGSize(width: 88.0, height: 88.0) let animationSize = CGSize(width: 100.0, height: 100.0)
let titleSize = self.titleNode.updateLayout(CGSize(width: layout.size.width, height: CGFloat.greatestFiniteMagnitude)) let titleSize = self.titleNode.updateLayout(CGSize(width: layout.size.width, height: CGFloat.greatestFiniteMagnitude))
let currentOptionSize = self.currentOptionNode.updateLayout(CGSize(width: layout.size.width - 28.0, height: CGFloat.greatestFiniteMagnitude)) let currentOptionSize = self.currentOptionNode.updateLayout(CGSize(width: layout.size.width - 48.0, height: CGFloat.greatestFiniteMagnitude))
let currentOptionInfoSize = self.currentOptionInfoNode.measure(CGSize(width: layout.size.width - 28.0, height: CGFloat.greatestFiniteMagnitude)) let currentOptionInfoSize = self.currentOptionInfoNode.measure(CGSize(width: layout.size.width - 48.0, height: CGFloat.greatestFiniteMagnitude))
let nextOptionSize = self.nextOptionTitleNode.updateLayout(CGSize(width: layout.size.width, height: CGFloat.greatestFiniteMagnitude)) let nextOptionSize = self.nextOptionTitleNode.updateLayout(CGSize(width: layout.size.width, height: CGFloat.greatestFiniteMagnitude))
let codeLength: Int let codeLength: Int
@ -323,6 +328,8 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
theme: CodeInputView.Theme( theme: CodeInputView.Theme(
inactiveBorder: self.theme.list.itemPlainSeparatorColor.argb, inactiveBorder: self.theme.list.itemPlainSeparatorColor.argb,
activeBorder: self.theme.list.itemAccentColor.argb, activeBorder: self.theme.list.itemAccentColor.argb,
succeedBorder: self.theme.list.itemDisclosureActions.constructive.fillColor.argb,
failedBorder: self.theme.list.itemDestructiveColor.argb,
foreground: self.theme.list.itemPrimaryTextColor.argb, foreground: self.theme.list.itemPrimaryTextColor.argb,
isDark: self.theme.overallDarkAppearance isDark: self.theme.overallDarkAppearance
), ),
@ -372,9 +379,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
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: 18.0, maxValue: 18.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
items.append(AuthorizationLayoutItem(node: self.currentOptionNode, size: currentOptionSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 10.0, maxValue: 10.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) items.append(AuthorizationLayoutItem(node: self.currentOptionNode, size: currentOptionSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 10.0, maxValue: 10.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
items.append(AuthorizationLayoutItem(node: self.codeInputView, size: codeFieldSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 40.0, maxValue: 100.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) items.append(AuthorizationLayoutItem(node: self.codeInputView, size: codeFieldSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 30.0, maxValue: 30.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: 40.0, maxValue: 100.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
//items.append(AuthorizationLayoutItem(node: self.codeSeparatorNode, size: CGSize(width: layout.size.width - 88.0, height: UIScreenPixel), spacingBefore: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
items.append(AuthorizationLayoutItem(node: self.nextOptionButtonNode, size: nextOptionSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 50.0, maxValue: 120.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) items.append(AuthorizationLayoutItem(node: self.nextOptionButtonNode, size: nextOptionSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 50.0, maxValue: 120.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
case .missedCall: case .missedCall:
@ -393,15 +398,11 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
}) })
} }
// items.append(AuthorizationLayoutItem(node: self.titleIconNode, size: self.titleIconNode.image!.size, spacingBefore: AuthorizationLayoutItemSpacing(weight: 41.0, maxValue: 41.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
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: 18.0, maxValue: 18.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
items.append(AuthorizationLayoutItem(node: self.currentOptionNode, size: currentOptionSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 10.0, maxValue: 10.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) items.append(AuthorizationLayoutItem(node: self.currentOptionNode, size: currentOptionSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 10.0, maxValue: 10.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
items.append(AuthorizationLayoutItem(node: self.codeInputView, size: codeFieldSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 40.0, maxValue: 100.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) items.append(AuthorizationLayoutItem(node: self.codeInputView, size: codeFieldSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 40.0, maxValue: 100.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: 40.0, maxValue: 100.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
items.append(AuthorizationLayoutItem(node: self.codeSeparatorNode, size: CGSize(width: layout.size.width - 88.0, height: UIScreenPixel), spacingBefore: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))*/
items.append(AuthorizationLayoutItem(node: self.currentOptionInfoNode, size: currentOptionInfoSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 60.0, maxValue: 100.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) items.append(AuthorizationLayoutItem(node: self.currentOptionInfoNode, size: currentOptionInfoSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 60.0, maxValue: 100.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
items.append(AuthorizationLayoutItem(node: self.nextOptionButtonNode, size: nextOptionSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 50.0, maxValue: 120.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) items.append(AuthorizationLayoutItem(node: self.nextOptionButtonNode, size: nextOptionSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 50.0, maxValue: 120.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
@ -467,12 +468,38 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
func activateInput() { func activateInput() {
let _ = self.codeInputView.becomeFirstResponder() let _ = self.codeInputView.becomeFirstResponder()
//self.codeField.textField.becomeFirstResponder()
} }
func animateError() { func animateError() {
self.codeInputView.layer.addShakeAnimation() self.codeInputView.layer.addShakeAnimation()
//self.codeField.layer.addShakeAnimation() }
func animateError(text: String) {
self.codeInputView.animateError()
self.codeInputView.layer.addShakeAnimation(amplitude: -30.0, duration: 0.5, count: 6, decay: true)
self.errorTextNode.attributedText = NSAttributedString(string: text, font: Font.regular(17.0), textColor: self.theme.list.itemDestructiveColor, paragraphAlignment: .center)
if let (layout, _) = self.layoutArguments {
let errorTextSize = self.errorTextNode.updateLayout(CGSize(width: layout.size.width - 48.0, height: .greatestFiniteMagnitude))
self.errorTextNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - errorTextSize.width) / 2.0), y: self.codeInputView.frame.maxY + 28.0), size: errorTextSize)
}
self.errorTextNode.alpha = 1.0
self.errorTextNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
self.errorTextNode.layer.addShakeAnimation(amplitude: -8.0, duration: 0.5, count: 6, decay: true)
Queue.mainQueue().after(0.85) {
self.errorTextNode.alpha = 0.0
self.errorTextNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15)
}
}
func animateSuccess() {
self.codeInputView.animateSuccess()
let values: [NSNumber] = [1.0, 1.1, 1.0]
self.codeInputView.layer.animateKeyframes(values: values, duration: 0.4, keyPath: "transform.scale")
} }
@objc func codeFieldTextChanged(_ textField: UITextField) { @objc func codeFieldTextChanged(_ textField: UITextField) {

View File

@ -68,7 +68,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
navigationStatusBar = .white navigationStatusBar = .white
} }
super.init(mode: .single, theme: NavigationControllerTheme(statusBar: navigationStatusBar, navigationBar: AuthorizationSequenceController.navigationBarTheme(presentationData.theme), emptyAreaColor: .black)) super.init(mode: .single, theme: NavigationControllerTheme(statusBar: navigationStatusBar, navigationBar: AuthorizationSequenceController.navigationBarTheme(presentationData.theme), isFlat: true, emptyAreaColor: .black))
self.stateDisposable = (TelegramEngineUnauthorized(account: self.account).auth.state() self.stateDisposable = (TelegramEngineUnauthorized(account: self.account).auth.state()
|> map { state -> InnerState in |> map { state -> InnerState in
@ -130,7 +130,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
return controller return controller
} }
private func phoneEntryController(countryCode: Int32, number: String) -> AuthorizationSequencePhoneEntryController { private func phoneEntryController(countryCode: Int32, number: String, splahController: AuthorizationSequenceSplashController?) -> AuthorizationSequencePhoneEntryController {
var currentController: AuthorizationSequencePhoneEntryController? var currentController: AuthorizationSequencePhoneEntryController?
for c in self.viewControllers { for c in self.viewControllers {
if let c = c as? AuthorizationSequencePhoneEntryController { if let c = c as? AuthorizationSequencePhoneEntryController {
@ -156,6 +156,9 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .empty)).start() let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .empty)).start()
} }
}) })
if let splahController = splahController {
controller.animateWithSplashController(splahController)
}
controller.accountUpdated = { [weak self] updatedAccount in controller.accountUpdated = { [weak self] updatedAccount in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -393,35 +396,39 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
let _ = beginSignUp(account: strongSelf.account, data: data).start() let _ = beginSignUp(account: strongSelf.account, data: data).start()
} }
case .loggedIn: case .loggedIn:
break controller?.animateSuccess()
} }
}, error: { error in }, error: { error in
Queue.mainQueue().async { Queue.mainQueue().async {
if let strongSelf = self, let controller = controller { if let strongSelf = self, let controller = controller {
controller.inProgress = false controller.inProgress = false
var resetCode = false if case .invalidCode = error {
let text: String controller.animateError(text: strongSelf.presentationData.strings.Login_WrongCodeError)
switch error { } else {
case .limitExceeded: var resetCode = false
resetCode = true let text: String
text = strongSelf.presentationData.strings.Login_CodeFloodError switch error {
case .invalidCode: case .limitExceeded:
resetCode = true resetCode = true
text = strongSelf.presentationData.strings.Login_InvalidCodeError text = strongSelf.presentationData.strings.Login_CodeFloodError
case .generic: case .invalidCode:
text = strongSelf.presentationData.strings.Login_UnknownError resetCode = true
case .codeExpired: text = strongSelf.presentationData.strings.Login_InvalidCodeError
text = strongSelf.presentationData.strings.Login_CodeExpired case .generic:
let account = strongSelf.account text = strongSelf.presentationData.strings.Login_UnknownError
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty)).start() case .codeExpired:
text = strongSelf.presentationData.strings.Login_CodeExpired
let account = strongSelf.account
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty)).start()
}
if resetCode {
controller.resetCode()
}
controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
} }
if resetCode {
controller.resetCode()
}
controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
} }
} }
})) }))
@ -985,7 +992,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
if self.otherAccountPhoneNumbers.1.isEmpty { if self.otherAccountPhoneNumbers.1.isEmpty {
controllers.append(self.splashController()) controllers.append(self.splashController())
} else { } else {
controllers.append(self.phoneEntryController(countryCode: defaultCountryCode(), number: "")) controllers.append(self.phoneEntryController(countryCode: defaultCountryCode(), number: "", splahController: nil))
} }
self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty) self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty)
} }
@ -994,14 +1001,21 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
if !self.otherAccountPhoneNumbers.1.isEmpty { if !self.otherAccountPhoneNumbers.1.isEmpty {
controllers.append(self.splashController()) controllers.append(self.splashController())
} }
controllers.append(self.phoneEntryController(countryCode: countryCode, number: number)) var previousSplashController: AuthorizationSequenceSplashController?
self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty) for c in self.viewControllers {
if let c = c as? AuthorizationSequenceSplashController {
previousSplashController = c
break
}
}
controllers.append(self.phoneEntryController(countryCode: countryCode, number: number, splahController: previousSplashController))
self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty && previousSplashController == nil)
case let .confirmationCodeEntry(number, type, _, timeout, nextType, _): case let .confirmationCodeEntry(number, type, _, timeout, nextType, _):
var controllers: [ViewController] = [] var controllers: [ViewController] = []
if !self.otherAccountPhoneNumbers.1.isEmpty { if !self.otherAccountPhoneNumbers.1.isEmpty {
controllers.append(self.splashController()) controllers.append(self.splashController())
} }
controllers.append(self.phoneEntryController(countryCode: defaultCountryCode(), number: "")) controllers.append(self.phoneEntryController(countryCode: defaultCountryCode(), number: "", splahController: nil))
if case let .emailSetupRequired(appleSignInAllowed) = type { if case let .emailSetupRequired(appleSignInAllowed) = type {
controllers.append(self.emailSetupController(number: number, appleSignInAllowed: appleSignInAllowed)) controllers.append(self.emailSetupController(number: number, appleSignInAllowed: appleSignInAllowed))
} else { } else {

View File

@ -17,7 +17,7 @@ final class AuthorizationDividerNode: ASDisplayNode {
init(theme: PresentationTheme, strings: PresentationStrings) { init(theme: PresentationTheme, strings: PresentationStrings) {
self.titleNode = ImmediateTextNode() self.titleNode = ImmediateTextNode()
self.titleNode.maximumNumberOfLines = 1 self.titleNode.maximumNumberOfLines = 1
self.titleNode.attributedText = NSAttributedString(string: "or", font: Font.regular(17.0), textColor: theme.list.itemSecondaryTextColor) self.titleNode.attributedText = NSAttributedString(string: strings.Login_Or, font: Font.regular(17.0), textColor: theme.list.itemSecondaryTextColor)
self.leftLineNode = ASDisplayNode() self.leftLineNode = ASDisplayNode()
self.leftLineNode.backgroundColor = theme.list.itemSecondaryTextColor self.leftLineNode.backgroundColor = theme.list.itemSecondaryTextColor
@ -90,20 +90,20 @@ final class AuthorizationSequenceEmailEntryControllerNode: ASDisplayNode, UIText
self.titleNode = ASTextNode() self.titleNode = ASTextNode()
self.titleNode.isUserInteractionEnabled = false self.titleNode.isUserInteractionEnabled = false
self.titleNode.displaysAsynchronously = false self.titleNode.displaysAsynchronously = false
self.titleNode.attributedText = NSAttributedString(string: "Add Email", font: Font.light(30.0), textColor: self.theme.list.itemPrimaryTextColor) self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_AddEmailTitle, font: Font.light(30.0), textColor: self.theme.list.itemPrimaryTextColor)
self.noticeNode = ASTextNode() self.noticeNode = ASTextNode()
self.noticeNode.isUserInteractionEnabled = false self.noticeNode.isUserInteractionEnabled = false
self.noticeNode.displaysAsynchronously = false self.noticeNode.displaysAsynchronously = false
self.noticeNode.lineSpacing = 0.1 self.noticeNode.lineSpacing = 0.1
self.noticeNode.attributedText = NSAttributedString(string: "Please enter your valid email address to protect your account.", font: Font.regular(16.0), textColor: self.theme.list.itemPrimaryTextColor, paragraphAlignment: .center) self.noticeNode.attributedText = NSAttributedString(string: self.strings.Login_AddEmailText, font: Font.regular(16.0), textColor: self.theme.list.itemPrimaryTextColor, paragraphAlignment: .center)
if #available(iOS 13.0, *) { if #available(iOS 13.0, *) {
self.signInWithAppleButton = ASAuthorizationAppleIDButton(authorizationButtonType: .signIn, authorizationButtonStyle: theme.overallDarkAppearance ? .white : .black) self.signInWithAppleButton = ASAuthorizationAppleIDButton(authorizationButtonType: .signIn, authorizationButtonStyle: theme.overallDarkAppearance ? .white : .black)
(self.signInWithAppleButton as? ASAuthorizationAppleIDButton)?.cornerRadius = 11 (self.signInWithAppleButton as? ASAuthorizationAppleIDButton)?.cornerRadius = 11
} }
self.proceedNode = SolidRoundedButtonNode(title: "Continue", theme: SolidRoundedButtonTheme(theme: self.theme), height: 50.0, cornerRadius: 11.0, gloss: false) self.proceedNode = SolidRoundedButtonNode(title: self.strings.Login_Continue, theme: SolidRoundedButtonTheme(theme: self.theme), height: 50.0, cornerRadius: 11.0, gloss: false)
self.codeSeparatorNode = ASDisplayNode() self.codeSeparatorNode = ASDisplayNode()
self.codeSeparatorNode.isLayerBacked = true self.codeSeparatorNode.isLayerBacked = true
@ -120,7 +120,7 @@ final class AuthorizationSequenceEmailEntryControllerNode: ASDisplayNode, UIText
self.codeField.textField.keyboardAppearance = self.theme.rootController.keyboardColor.keyboardAppearance self.codeField.textField.keyboardAppearance = self.theme.rootController.keyboardColor.keyboardAppearance
self.codeField.textField.disableAutomaticKeyboardHandling = [.forward, .backward] self.codeField.textField.disableAutomaticKeyboardHandling = [.forward, .backward]
self.codeField.textField.tintColor = self.theme.list.itemAccentColor self.codeField.textField.tintColor = self.theme.list.itemAccentColor
self.codeField.textField.placeholder = "Enter Your Email" self.codeField.textField.placeholder = self.strings.Login_AddEmailPlaceholder
self.dividerNode = AuthorizationDividerNode(theme: self.theme, strings: self.strings) self.dividerNode = AuthorizationDividerNode(theme: self.theme, strings: self.strings)
@ -193,9 +193,9 @@ final class AuthorizationSequenceEmailEntryControllerNode: ASDisplayNode, UIText
insets.bottom += max(inputHeight, insets.bottom) insets.bottom += max(inputHeight, insets.bottom)
} }
self.titleNode.attributedText = NSAttributedString(string: "Add Email", font: Font.bold(28.0), textColor: self.theme.list.itemPrimaryTextColor) self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_AddEmailTitle, font: Font.bold(28.0), textColor: self.theme.list.itemPrimaryTextColor)
let animationSize = CGSize(width: 88.0, height: 88.0) let animationSize = CGSize(width: 100.0, height: 100.0)
let titleSize = self.titleNode.measure(CGSize(width: layout.size.width, height: CGFloat.greatestFiniteMagnitude)) let titleSize = self.titleNode.measure(CGSize(width: layout.size.width, height: CGFloat.greatestFiniteMagnitude))
let noticeSize = self.noticeNode.measure(CGSize(width: layout.size.width - 80.0, height: CGFloat.greatestFiniteMagnitude)) let noticeSize = self.noticeNode.measure(CGSize(width: layout.size.width - 80.0, height: CGFloat.greatestFiniteMagnitude))

View File

@ -97,6 +97,17 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
} }
} }
private var shouldAnimateIn = false
private var transitionInArguments: (buttonFrame: CGRect, animationSnapshot: UIView, textSnapshot: UIView)?
func animateWithSplashController(_ controller: AuthorizationSequenceSplashController) {
self.shouldAnimateIn = true
if let animationSnapshot = controller.animationSnapshot, let textSnapshot = controller.textSnaphot {
self.transitionInArguments = (controller.buttonFrame, animationSnapshot, textSnapshot)
}
}
override public func loadDisplayNode() { override public func loadDisplayNode() {
self.displayNode = AuthorizationSequencePhoneEntryControllerNode(sharedContext: self.sharedContext, account: self.account, strings: self.presentationData.strings, theme: self.presentationData.theme, debugAction: { [weak self] in self.displayNode = AuthorizationSequencePhoneEntryControllerNode(sharedContext: self.sharedContext, account: self.account, strings: self.presentationData.strings, theme: self.presentationData.theme, debugAction: { [weak self] in
guard let strongSelf = self else { guard let strongSelf = self else {
@ -146,22 +157,42 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
}) })
} }
private var animatingIn = false
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
self.controllerNode.activateInput() if self.shouldAnimateIn {
self.animatingIn = true
if let (buttonFrame, animationSnapshot, textSnapshot) = self.transitionInArguments {
self.controllerNode.willAnimateIn(buttonFrame: buttonFrame, animationSnapshot: animationSnapshot, textSnapshot: textSnapshot)
}
Queue.mainQueue().justDispatch {
self.controllerNode.activateInput()
}
} else {
self.controllerNode.activateInput()
}
} }
override func viewDidAppear(_ animated: Bool) { override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
self.controllerNode.activateInput() if !self.animatingIn {
self.controllerNode.activateInput()
}
} }
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition) super.containerLayoutUpdated(layout, transition: transition)
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition) self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
if self.shouldAnimateIn, let inputHeight = layout.inputHeight, inputHeight > 0.0 {
if let (buttonFrame, animationSnapshot, textSnapshot) = self.transitionInArguments {
self.shouldAnimateIn = false
self.controllerNode.animateIn(buttonFrame: buttonFrame, animationSnapshot: animationSnapshot, textSnapshot: textSnapshot)
}
}
} }
@objc func nextPressed() { @objc func nextPressed() {

View File

@ -154,12 +154,18 @@ private final class PhoneAndCountryNode: ASDisplayNode {
let flagString = emojiFlagForISOCountryCode(name) let flagString = emojiFlagForISOCountryCode(name)
let localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(name, strings: strongSelf.strings) ?? countryName let localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(name, strings: strongSelf.strings) ?? countryName
strongSelf.countryButton.setTitle("\(flagString) \(localizedName)", with: Font.regular(20.0), with: theme.list.itemAccentColor, for: []) strongSelf.countryButton.setTitle("\(flagString) \(localizedName)", with: Font.regular(20.0), with: theme.list.itemAccentColor, for: [])
strongSelf.phoneInputNode.numberField.textField.attributedPlaceholder = NSAttributedString(string: strings.Login_PhonePlaceholder, font: Font.regular(20.0), textColor: theme.list.itemPlaceholderTextColor)
if strongSelf.phoneInputNode.mask == nil {
strongSelf.phoneInputNode.numberField.textField.attributedPlaceholder = NSAttributedString(string: strings.Login_PhonePlaceholder, font: Font.regular(20.0), textColor: theme.list.itemPlaceholderTextColor)
}
} else if let code = Int(code), let (countryId, countryName) = countryCodeToIdAndName[code] { } else if let code = Int(code), let (countryId, countryName) = countryCodeToIdAndName[code] {
let flagString = emojiFlagForISOCountryCode(countryId) let flagString = emojiFlagForISOCountryCode(countryId)
let localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(countryId, strings: strongSelf.strings) ?? countryName let localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(countryId, strings: strongSelf.strings) ?? countryName
strongSelf.countryButton.setTitle("\(flagString) \(localizedName)", with: Font.regular(20.0), with: theme.list.itemAccentColor, for: []) strongSelf.countryButton.setTitle("\(flagString) \(localizedName)", with: Font.regular(20.0), with: theme.list.itemAccentColor, for: [])
strongSelf.phoneInputNode.numberField.textField.attributedPlaceholder = NSAttributedString(string: strings.Login_PhonePlaceholder, font: Font.regular(20.0), textColor: theme.list.itemPlaceholderTextColor)
if strongSelf.phoneInputNode.mask == nil {
strongSelf.phoneInputNode.numberField.textField.attributedPlaceholder = NSAttributedString(string: strings.Login_PhonePlaceholder, font: Font.regular(20.0), textColor: theme.list.itemPlaceholderTextColor)
}
} else { } else {
strongSelf.countryButton.setTitle(strings.Login_SelectCountry, with: Font.regular(20.0), with: theme.list.itemAccentColor, for: []) strongSelf.countryButton.setTitle(strings.Login_SelectCountry, with: Font.regular(20.0), with: theme.list.itemAccentColor, for: [])
strongSelf.phoneInputNode.mask = nil strongSelf.phoneInputNode.mask = nil
@ -330,7 +336,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
self.phoneAndCountryNode = PhoneAndCountryNode(strings: strings, theme: theme) self.phoneAndCountryNode = PhoneAndCountryNode(strings: strings, theme: theme)
self.proceedNode = SolidRoundedButtonNode(title: "Continue", theme: SolidRoundedButtonTheme(theme: self.theme), height: 50.0, cornerRadius: 11.0, gloss: false) self.proceedNode = SolidRoundedButtonNode(title: self.strings.Login_Continue, theme: SolidRoundedButtonTheme(theme: self.theme), height: 50.0, cornerRadius: 11.0, gloss: false)
self.proceedNode.progressType = .embedded self.proceedNode.progressType = .embedded
super.init() super.init()
@ -380,6 +386,64 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
#endif #endif
} }
private var animationSnapshotView: UIView?
private var textSnapshotView: UIView?
private var forcedButtonFrame: CGRect?
func willAnimateIn(buttonFrame: CGRect, animationSnapshot: UIView, textSnapshot: UIView) {
self.proceedNode.frame = buttonFrame
self.proceedNode.title = "Start Messaging"
self.animationSnapshotView = animationSnapshot
self.view.insertSubview(animationSnapshot, at: 0)
self.textSnapshotView = textSnapshot
self.view.insertSubview(textSnapshot, at: 0)
let nodes: [ASDisplayNode] = [
self.animationNode,
self.titleNode,
self.noticeNode,
self.phoneAndCountryNode,
self.contactSyncNode
]
for node in nodes {
node.alpha = 0.0
}
}
func animateIn(buttonFrame: CGRect, 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
})
self.animationSnapshotView?.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -100.0), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
self.textSnapshotView?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak self] _ in
self?.textSnapshotView?.removeFromSuperview()
self?.textSnapshotView = nil
})
self.textSnapshotView?.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -140.0), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
let nodes: [ASDisplayNode] = [
self.animationNode,
self.titleNode,
self.noticeNode,
self.phoneAndCountryNode,
self.contactSyncNode
]
for node in nodes {
node.alpha = 1.0
node.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
}
}
func updateCountryCode() { func updateCountryCode() {
self.phoneAndCountryNode.phoneInputNode.codeAndNumber = self.codeAndNumber self.phoneAndCountryNode.phoneInputNode.codeAndNumber = self.codeAndNumber
} }
@ -396,7 +460,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
let inset: CGFloat = 24.0 let inset: CGFloat = 24.0
let animationSize = CGSize(width: 88.0, height: 88.0) let animationSize = CGSize(width: 100.0, height: 100.0)
let titleSize = self.titleNode.measure(CGSize(width: layout.size.width, height: CGFloat.greatestFiniteMagnitude)) let titleSize = self.titleNode.measure(CGSize(width: layout.size.width, height: CGFloat.greatestFiniteMagnitude))
let noticeSize = self.noticeNode.measure(CGSize(width: min(274.0, layout.size.width - 28.0), height: CGFloat.greatestFiniteMagnitude)) let noticeSize = self.noticeNode.measure(CGSize(width: min(274.0, layout.size.width - 28.0), height: CGFloat.greatestFiniteMagnitude))
let proceedHeight = self.proceedNode.updateLayout(width: layout.size.width - inset * 2.0, transition: transition) let proceedHeight = self.proceedNode.updateLayout(width: layout.size.width - inset * 2.0, transition: transition)
@ -411,12 +475,19 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
let contactSyncSize = self.contactSyncNode.updateLayout(width: layout.size.width) let contactSyncSize = self.contactSyncNode.updateLayout(width: layout.size.width)
if self.hasOtherAccounts { if self.hasOtherAccounts {
self.contactSyncNode.isHidden = false self.contactSyncNode.isHidden = false
items.append(AuthorizationLayoutItem(node: self.contactSyncNode, size: contactSyncSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 16.0, maxValue: 16.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))) items.append(AuthorizationLayoutItem(node: self.contactSyncNode, size: contactSyncSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 14.0, maxValue: 14.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
} else { } else {
self.contactSyncNode.isHidden = true self.contactSyncNode.isHidden = true
} }
transition.updateFrame(node: self.proceedNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - proceedSize.width) / 2.0), y: layout.size.height - insets.bottom - proceedSize.height - inset), size: proceedSize)) let buttonFrame: CGRect
if let forcedButtonFrame = self.forcedButtonFrame, (layout.inputHeight ?? 0.0).isZero {
buttonFrame = forcedButtonFrame
} else {
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)
self.animationNode.updateLayout(size: animationSize) self.animationNode.updateLayout(size: animationSize)

View File

@ -141,7 +141,7 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel
self.addPhotoButton.addSubnode(self.currentPhotoNode) self.addPhotoButton.addSubnode(self.currentPhotoNode)
self.addPhotoButton.allowsGroupOpacity = true self.addPhotoButton.allowsGroupOpacity = true
self.proceedNode = SolidRoundedButtonNode(title: "Continue", theme: SolidRoundedButtonTheme(theme: self.theme), height: 50.0, cornerRadius: 11.0, gloss: false) self.proceedNode = SolidRoundedButtonNode(title: self.strings.Login_Continue, theme: SolidRoundedButtonTheme(theme: self.theme), height: 50.0, cornerRadius: 11.0, gloss: false)
super.init() super.init()

View File

@ -7,7 +7,7 @@ import TelegramCore
import SwiftSignalKit import SwiftSignalKit
import TelegramPresentationData import TelegramPresentationData
import LegacyComponents import LegacyComponents
import SolidRoundedButtonNode
import RMIntro import RMIntro
final class AuthorizationSequenceSplashController: ViewController { final class AuthorizationSequenceSplashController: ViewController {
@ -28,6 +28,8 @@ final class AuthorizationSequenceSplashController: ViewController {
private let suggestedLocalization = Promise<SuggestedLocalizationInfo?>() private let suggestedLocalization = Promise<SuggestedLocalizationInfo?>()
private let activateLocalizationDisposable = MetaDisposable() private let activateLocalizationDisposable = MetaDisposable()
private let startButton: SolidRoundedButtonNode
init(accountManager: AccountManager<TelegramAccountManagerTypes>, account: UnauthorizedAccount, theme: PresentationTheme) { init(accountManager: AccountManager<TelegramAccountManagerTypes>, account: UnauthorizedAccount, theme: PresentationTheme) {
self.accountManager = accountManager self.accountManager = accountManager
self.account = account self.account = account
@ -68,7 +70,9 @@ final class AuthorizationSequenceSplashController: ViewController {
}) })
}) })
self.controller = RMIntroViewController(backgroundColor: theme.list.plainBackgroundColor, primaryColor: theme.list.itemPrimaryTextColor, buttonColor: theme.intro.startButtonColor, accentColor: theme.list.itemAccentColor, regularDotColor: theme.intro.dotColor, highlightedDotColor: theme.list.itemPrimaryTextColor, suggestedLocalizationSignal: localizationSignal) self.controller = RMIntroViewController(backgroundColor: theme.list.plainBackgroundColor, primaryColor: theme.list.itemPrimaryTextColor, buttonColor: theme.intro.startButtonColor, accentColor: theme.list.itemAccentColor, regularDotColor: theme.intro.dotColor, highlightedDotColor: theme.list.itemAccentColor, suggestedLocalizationSignal: localizationSignal)
self.startButton = SolidRoundedButtonNode(title: "Start Messaging", theme: SolidRoundedButtonTheme(theme: theme), height: 50.0, cornerRadius: 13.0, gloss: true)
super.init(navigationBarPresentationData: nil) super.init(navigationBarPresentationData: nil)
@ -84,6 +88,15 @@ final class AuthorizationSequenceSplashController: ViewController {
self?.activateLocalization(code) self?.activateLocalization(code)
} }
} }
self.startButton.pressed = { [weak self] in
self?.activateLocalization("en")
}
self.controller.createStartButton = { [weak self] width in
let _ = self?.startButton.updateLayout(width: width, transition: .immediate)
return self?.startButton.view
}
} }
required init(coder aDecoder: NSCoder) { required init(coder aDecoder: NSCoder) {
@ -99,20 +112,32 @@ final class AuthorizationSequenceSplashController: ViewController {
self.displayNodeDidLoad() self.displayNodeDidLoad()
} }
var buttonFrame: CGRect {
return self.startButton.frame
}
var animationSnapshot: UIView? {
return self.controller.createAnimationSnapshot()
}
var textSnaphot: UIView? {
return self.controller.createTextSnapshot()
}
private func addControllerIfNeeded() { private func addControllerIfNeeded() {
if !controller.isViewLoaded || controller.view.superview == nil { if !self.controller.isViewLoaded || self.controller.view.superview == nil {
self.displayNode.view.addSubview(controller.view) self.displayNode.view.addSubview(self.controller.view)
if let layout = self.validLayout { if let layout = self.validLayout {
controller.view.frame = CGRect(origin: CGPoint(), size: layout.size) controller.view.frame = CGRect(origin: CGPoint(), size: layout.size)
} }
controller.viewDidAppear(false) self.controller.viewDidAppear(false)
} }
} }
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
self.addControllerIfNeeded() self.addControllerIfNeeded()
controller.viewWillAppear(false) self.controller.viewWillAppear(false)
} }
override func viewDidAppear(_ animated: Bool) { override func viewDidAppear(_ animated: Bool) {
@ -182,6 +207,7 @@ final class AuthorizationSequenceSplashController: ViewController {
} }
strongSelf.controller.isEnabled = false strongSelf.controller.isEnabled = false
strongSelf.startButton.alpha = 0.6
let accountManager = strongSelf.accountManager let accountManager = strongSelf.accountManager
strongSelf.activateLocalizationDisposable.set(TelegramEngineUnauthorized(account: strongSelf.account).localization.downloadAndApplyLocalization(accountManager: accountManager, languageCode: code).start(completed: { strongSelf.activateLocalizationDisposable.set(TelegramEngineUnauthorized(account: strongSelf.account).localization.downloadAndApplyLocalization(accountManager: accountManager, languageCode: code).start(completed: {
@ -202,6 +228,7 @@ final class AuthorizationSequenceSplashController: ViewController {
} }
|> deliverOnMainQueue).start(next: { strings in |> deliverOnMainQueue).start(next: { strings in
self?.controller.isEnabled = true self?.controller.isEnabled = true
self?.startButton.alpha = 1.0
self?.pressNext(strings: strings) self?.pressNext(strings: strings)
}) })
})) }))