mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit '7f2ab1788ff168b788f20c4896822d74f3944214'
This commit is contained in:
commit
e26c4a6bf0
@ -7979,3 +7979,22 @@ Sorry for the inconvenience.";
|
||||
"Login.SelectCountry" = "Country";
|
||||
|
||||
"ReportPeer.ReportReaction" = "Report Reaction";
|
||||
|
||||
"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.";
|
||||
|
@ -13,4 +13,6 @@ public protocol ChatListController: ViewController {
|
||||
func deactivateSearch(animated: Bool)
|
||||
func activateCompose()
|
||||
func maybeAskForPeerChatRemoval(peer: EngineRenderedPeer, joined: Bool, deleteGloballyIfPossible: Bool, completion: @escaping (Bool) -> Void, removed: @escaping () -> Void)
|
||||
|
||||
func playSignUpCompletedAnimation()
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
self.clipNode = ASDisplayNode()
|
||||
|
||||
var controllerRemovedImpl: ((ViewController) -> Void)?
|
||||
self.container = NavigationContainer(controllerRemoved: { c in
|
||||
self.container = NavigationContainer(isFlat: false, controllerRemoved: { c in
|
||||
controllerRemovedImpl?(c)
|
||||
})
|
||||
self.container.clipsToBounds = true
|
||||
|
@ -6,15 +6,17 @@ import TelegramPresentationData
|
||||
import TextFormat
|
||||
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 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 {
|
||||
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:
|
||||
let body = MarkdownAttributeSet(font: Font.regular(fontSize), textColor: primaryColor)
|
||||
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)
|
||||
return parseMarkdownIntoAttributedString(strings.Login_EnterCodeTelegramText(phoneNumber).string, attributes: attributes, textAlignment: .center)
|
||||
case .missedCall:
|
||||
let body = MarkdownAttributeSet(font: Font.regular(fontSize), textColor: primaryColor)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(fontSize), textColor: primaryColor)
|
||||
@ -26,8 +28,7 @@ public func authorizationCurrentOptionText(_ type: SentAuthorizationCodeType, st
|
||||
case .emailSetupRequired:
|
||||
return NSAttributedString(string: "", font: Font.regular(fontSize), textColor: primaryColor, paragraphAlignment: .center)
|
||||
case let .email(emailPattern, _, _, _, _):
|
||||
//TODO: localize
|
||||
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 mutableString = NSAttributedString(string: strings.Login_EnterCodeEmailText(email ?? emailPattern).string, font: Font.regular(fontSize), textColor: primaryColor, paragraphAlignment: .center).mutableCopy() as! NSMutableAttributedString
|
||||
let range = (mutableString.string as NSString).range(of: "*******")
|
||||
if range.location != NSNotFound {
|
||||
mutableString.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler), value: true, range: range)
|
||||
|
@ -30,6 +30,7 @@ import ComponentFlow
|
||||
import LottieAnimationComponent
|
||||
import ProgressIndicatorComponent
|
||||
import PremiumUI
|
||||
import ConfettiEffect
|
||||
import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
import EmojiStatusSelectionComponent
|
||||
@ -1584,7 +1585,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
|
||||
override public func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
|
||||
self.didAppear = true
|
||||
|
||||
self.chatListDisplayNode.containerNode.updateEnableAdjacentFilterLoading(true)
|
||||
@ -3462,6 +3463,17 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
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 {
|
||||
|
@ -2,23 +2,30 @@ import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import PhoneNumberFormat
|
||||
|
||||
public final class CodeInputView: ASDisplayNode, UITextFieldDelegate {
|
||||
public struct Theme: Equatable {
|
||||
public var inactiveBorder: UInt32
|
||||
public var activeBorder: UInt32
|
||||
public var succeedBorder: UInt32
|
||||
public var failedBorder: UInt32
|
||||
public var foreground: UInt32
|
||||
public var isDark: Bool
|
||||
|
||||
public init(
|
||||
inactiveBorder: UInt32,
|
||||
activeBorder: UInt32,
|
||||
succeedBorder: UInt32,
|
||||
failedBorder: UInt32,
|
||||
foreground: UInt32,
|
||||
isDark: Bool
|
||||
) {
|
||||
self.inactiveBorder = inactiveBorder
|
||||
self.activeBorder = activeBorder
|
||||
self.succeedBorder = succeedBorder
|
||||
self.failedBorder = failedBorder
|
||||
self.foreground = foreground
|
||||
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
|
||||
self.text = text
|
||||
|
||||
@ -83,10 +90,10 @@ public final class CodeInputView: ASDisplayNode, UITextFieldDelegate {
|
||||
} else {
|
||||
if let copyView = self.textNode.view.snapshotContentTree() {
|
||||
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.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) {
|
||||
self.textValue = textField.text ?? ""
|
||||
self.updateItemViews(animated: true)
|
||||
@ -170,6 +199,11 @@ public final class CodeInputView: ASDisplayNode, UITextFieldDelegate {
|
||||
guard let count = self.count else {
|
||||
return false
|
||||
}
|
||||
|
||||
guard !self.isFailed else {
|
||||
return false
|
||||
}
|
||||
|
||||
var text = textField.text ?? ""
|
||||
guard let stringRange = Range(range, in: text) else {
|
||||
return false
|
||||
@ -220,6 +254,7 @@ public final class CodeInputView: ASDisplayNode, UITextFieldDelegate {
|
||||
return
|
||||
}
|
||||
|
||||
var delay: Double = 0.0
|
||||
for i in 0 ..< self.itemViews.count {
|
||||
let itemView = self.itemViews[i]
|
||||
let itemSize = itemView.bounds.size
|
||||
@ -233,14 +268,26 @@ public final class CodeInputView: ASDisplayNode, UITextFieldDelegate {
|
||||
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
|
||||
if i < self.textValue.count {
|
||||
itemText = String(self.textValue[self.textValue.index(self.textValue.startIndex, offsetBy: i)])
|
||||
} else {
|
||||
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.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
|
||||
if i < self.textValue.count {
|
||||
itemText = String(self.textValue[self.textValue.index(self.textValue.startIndex, offsetBy: i)])
|
||||
|
@ -43,11 +43,17 @@ private func loadCountryCodes() -> [Country] {
|
||||
|
||||
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) ?? ""
|
||||
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)
|
||||
result.append(country)
|
||||
countriesByPrefix["\(code.code)"] = (country, code)
|
||||
@ -86,6 +92,7 @@ public func loadServerCountryCodes(accountManager: AccountManager<TelegramAccoun
|
||||
}
|
||||
}
|
||||
countryCodesByPrefix = countriesByPrefix
|
||||
|
||||
Queue.mainQueue().async {
|
||||
completion()
|
||||
}
|
||||
|
@ -38,7 +38,11 @@ private func loadCountryCodes() -> [(String, Int)] {
|
||||
|
||||
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) {
|
||||
result.append((countryId, countryCodeInt))
|
||||
|
@ -57,9 +57,13 @@ private func loadCountriesInfo() -> [(Int, String, String)] {
|
||||
|
||||
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 nameRange1 = data.range(of: endOfLine1, options: [], range: idRange.upperBound ..< data.endIndex)
|
||||
let nameRange2 = data.range(of: endOfLine2, 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: patternRange.upperBound ..< data.endIndex)
|
||||
var nameRange: Range<String.Index>?
|
||||
if let nameRange1 = nameRange1, let nameRange2 = nameRange2 {
|
||||
if nameRange1.lowerBound < nameRange2.lowerBound {
|
||||
@ -71,10 +75,10 @@ private func loadCountriesInfo() -> [(Int, String, String)] {
|
||||
nameRange = nameRange1 ?? nameRange2
|
||||
}
|
||||
if let nameRange = nameRange {
|
||||
countryName = String(data[idRange.upperBound ..< nameRange.lowerBound])
|
||||
countryName = String(data[patternRange.upperBound ..< nameRange.lowerBound])
|
||||
currentLocation = nameRange.upperBound
|
||||
} 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))
|
||||
|
@ -73,6 +73,7 @@ public final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelega
|
||||
var pending: PendingChild?
|
||||
}
|
||||
|
||||
private let isFlat: Bool
|
||||
public private(set) var controllers: [ViewController] = []
|
||||
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?
|
||||
|
||||
public init(controllerRemoved: @escaping (ViewController) -> Void) {
|
||||
public init(isFlat: Bool, controllerRemoved: @escaping (ViewController) -> Void) {
|
||||
self.isFlat = isFlat
|
||||
self.controllerRemoved = controllerRemoved
|
||||
|
||||
super.init()
|
||||
@ -224,7 +226,7 @@ public final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelega
|
||||
bottomController.viewWillAppear(true)
|
||||
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 top = strongSelf.state.top {
|
||||
strongSelf.syncKeyboard(leftEdge: top.value.displayNode.frame.minX, transition: transition)
|
||||
@ -459,7 +461,7 @@ public final class NavigationContainer: ASDisplayNode, UIGestureRecognizerDelega
|
||||
}
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
@ -142,6 +142,7 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
|
||||
private let mode: NavigationControllerMode
|
||||
private var theme: NavigationControllerTheme
|
||||
private let isFlat: Bool
|
||||
|
||||
var inCallNavigate: (() -> Void)?
|
||||
private var inCallStatusBar: StatusBar?
|
||||
@ -235,9 +236,10 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
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.theme = theme
|
||||
self.isFlat = isFlat
|
||||
self.backgroundDetailsMode = backgroundDetailsMode
|
||||
|
||||
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))
|
||||
flatContainer.update(layout: layout, canBeClosed: false, controllers: controllers, transition: transition)
|
||||
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)
|
||||
})
|
||||
flatContainer.statusBarStyleUpdated = { [weak self] transition in
|
||||
@ -782,7 +784,7 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
splitContainer.removeFromSupernode()
|
||||
}
|
||||
} else {
|
||||
let flatContainer = NavigationContainer(controllerRemoved: { [weak self] controller in
|
||||
let flatContainer = NavigationContainer(isFlat: self.isFlat, controllerRemoved: { [weak self] controller in
|
||||
self?.controllerRemoved(controller)
|
||||
})
|
||||
flatContainer.statusBarStyleUpdated = { [weak self] transition in
|
||||
|
@ -51,7 +51,7 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
|
||||
|
||||
self.scrollNode = ASScrollNode()
|
||||
|
||||
self.container = NavigationContainer(controllerRemoved: controllerRemoved)
|
||||
self.container = NavigationContainer(isFlat: false, controllerRemoved: controllerRemoved)
|
||||
self.container.clipsToBounds = true
|
||||
|
||||
super.init()
|
||||
|
@ -51,10 +51,10 @@ final class NavigationSplitContainer: ASDisplayNode {
|
||||
scrollToTop(.detail)
|
||||
}
|
||||
|
||||
self.masterContainer = NavigationContainer(controllerRemoved: controllerRemoved)
|
||||
self.masterContainer = NavigationContainer(isFlat: false, controllerRemoved: controllerRemoved)
|
||||
self.masterContainer.clipsToBounds = true
|
||||
|
||||
self.detailContainer = NavigationContainer(controllerRemoved: controllerRemoved)
|
||||
self.detailContainer = NavigationContainer(isFlat: false, controllerRemoved: controllerRemoved)
|
||||
self.detailContainer.clipsToBounds = true
|
||||
|
||||
self.separator = ASDisplayNode()
|
||||
|
@ -37,6 +37,7 @@ final class NavigationTransitionCoordinator {
|
||||
private let container: NavigationContainer
|
||||
private let transition: NavigationTransition
|
||||
let isInteractive: Bool
|
||||
let isFlat: Bool
|
||||
let topNode: ASDisplayNode
|
||||
let bottomNode: ASDisplayNode
|
||||
private let topNavigationBar: NavigationBar?
|
||||
@ -51,9 +52,10 @@ final class NavigationTransitionCoordinator {
|
||||
private var currentCompletion: (() -> 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.isInteractive = isInteractive
|
||||
self.isFlat = isFlat
|
||||
self.container = container
|
||||
self.didUpdateProgress = didUpdateProgress
|
||||
self.topNode = topNode
|
||||
@ -98,8 +100,10 @@ final class NavigationTransitionCoordinator {
|
||||
self.container.insertSubnode(bottomNode, belowSubnode: topNode)
|
||||
}
|
||||
|
||||
self.container.insertSubnode(self.dimNode, belowSubnode: topNode)
|
||||
self.container.insertSubnode(self.shadowNode, belowSubnode: self.dimNode)
|
||||
if !self.isFlat {
|
||||
self.container.insertSubnode(self.dimNode, belowSubnode: topNode)
|
||||
self.container.insertSubnode(self.shadowNode, belowSubnode: self.dimNode)
|
||||
}
|
||||
if let customTransitionNode = self.customTransitionNode {
|
||||
self.container.addSubnode(customTransitionNode)
|
||||
}
|
||||
@ -135,7 +139,7 @@ final class NavigationTransitionCoordinator {
|
||||
let containerSize = self.container.bounds.size
|
||||
|
||||
let topFrame = CGRect(origin: CGPoint(x: floorToScreenPixels(position * containerSize.width), y: 0.0), size: containerSize)
|
||||
let bottomFrame = CGRect(origin: CGPoint(x: ((position - 1.0) * containerSize.width * 0.3), y: 0.0), size: containerSize)
|
||||
let bottomFrame = CGRect(origin: CGPoint(x: self.isFlat ? -floorToScreenPixels((1.0 - position) * containerSize.width) : ((position - 1.0) * containerSize.width * 0.3), y: 0.0), size: containerSize)
|
||||
|
||||
var canInvokeCompletion = false
|
||||
var hadEarlyCompletion = false
|
||||
|
@ -203,7 +203,7 @@ public final class PhoneInputNode: ASDisplayNode, UITextFieldDelegate {
|
||||
self.countryCodeField.textField.returnKeyType = .next
|
||||
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
||||
self.countryCodeField.textField.keyboardType = .asciiCapableNumberPad
|
||||
self.countryCodeField.textField.textContentType = .telephoneNumber
|
||||
// self.countryCodeField.textField.textContentType = .telephoneNumber
|
||||
} else {
|
||||
self.countryCodeField.textField.keyboardType = .numberPad
|
||||
}
|
||||
@ -214,7 +214,7 @@ public final class PhoneInputNode: ASDisplayNode, UITextFieldDelegate {
|
||||
self.numberField.textField.font = font
|
||||
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
||||
self.numberField.textField.keyboardType = .asciiCapableNumberPad
|
||||
self.numberField.textField.textContentType = .telephoneNumber
|
||||
// self.numberField.textField.textContentType = .telephoneNumber
|
||||
} else {
|
||||
self.numberField.textField.keyboardType = .numberPad
|
||||
}
|
||||
|
@ -590,45 +590,14 @@ private final class PremiumGiftScreenComponent: CombinedComponent {
|
||||
strongSelf.paymentDisposable.set((inAppPurchaseManager.buyProduct(product.storeProduct, targetPeerId: strongSelf.peerId)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||
if let strongSelf = self, case .purchased = status {
|
||||
strongSelf.activationDisposable.set((strongSelf.context.account.postbox.peerView(id: strongSelf.context.account.peerId)
|
||||
|> castError(AssignAppStoreTransactionError.self)
|
||||
|> take(until: { view in
|
||||
if let peer = view.peers[view.peerId], peer.isPremium {
|
||||
return SignalTakeAction(passthrough: false, complete: true)
|
||||
} else {
|
||||
return SignalTakeAction(passthrough: false, complete: false)
|
||||
}
|
||||
})
|
||||
|> mapToSignal { _ -> Signal<Never, AssignAppStoreTransactionError> in
|
||||
return .never()
|
||||
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)
|
||||
}
|
||||
|> 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
|
||||
if let strongSelf = self {
|
||||
|
@ -61,6 +61,11 @@
|
||||
@property (nonatomic, copy) void (^startMessaging)(void);
|
||||
@property (nonatomic, copy) void (^startMessagingInAlternativeLanguage)(NSString *);
|
||||
|
||||
@property (nonatomic, copy) UIView *(^createStartButton)(CGFloat);
|
||||
|
||||
- (UIView *)createAnimationSnapshot;
|
||||
- (UIView *)createTextSnapshot;
|
||||
|
||||
@property (nonatomic) bool isEnabled;
|
||||
|
||||
- (void)startTimer;
|
||||
|
@ -24,7 +24,7 @@
|
||||
_headline=headline;
|
||||
|
||||
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.textColor = color;
|
||||
headlineLabel.textAlignment = NSTextAlignmentCenter;
|
||||
@ -32,14 +32,11 @@
|
||||
|
||||
|
||||
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
|
||||
style.lineSpacing = IPAD ? 6 : 5;
|
||||
style.lineSpacing = IPAD ? 4 : 3;
|
||||
style.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
style.alignment = NSTextAlignmentCenter;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
NSMutableArray *boldRanges = [[NSMutableArray alloc] init];
|
||||
|
||||
NSMutableString *cleanText = [[NSMutableString alloc] initWithString:description];
|
||||
@ -60,11 +57,9 @@
|
||||
[boldRanges addObject:[NSValue valueWithRange:NSMakeRange(startRange.location, endRange.location - startRange.location)]];
|
||||
}
|
||||
|
||||
|
||||
|
||||
_description = [[NSMutableAttributedString alloc]initWithString:cleanText];
|
||||
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)
|
||||
{
|
||||
[_description addAttributes:boldAttributes range:[nRange rangeValue]];
|
||||
@ -76,7 +71,7 @@
|
||||
[_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)];
|
||||
descriptionLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:IPAD ? 44/2 : 17];
|
||||
descriptionLabel.font = [UIFont systemFontOfSize:IPAD ? 22 : 17.0];
|
||||
descriptionLabel.attributedText = _description;
|
||||
descriptionLabel.numberOfLines=0;
|
||||
descriptionLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;
|
||||
|
@ -93,7 +93,6 @@ typedef enum {
|
||||
UIColor *_regularDotColor;
|
||||
UIColor *_highlightedDotColor;
|
||||
|
||||
UIButton *_startButton;
|
||||
TGModernButton *_alternativeLanguageButton;
|
||||
|
||||
SMetaDisposable *_localizationsDisposable;
|
||||
@ -102,6 +101,8 @@ typedef enum {
|
||||
SVariable *_alternativeLocalization;
|
||||
NSDictionary<NSString *, NSString *> *_englishStrings;
|
||||
|
||||
UIView *_wrapperView;
|
||||
|
||||
bool _loadedView;
|
||||
}
|
||||
@end
|
||||
@ -308,6 +309,9 @@ typedef enum {
|
||||
|
||||
[self loadGL];
|
||||
|
||||
_wrapperView = [[UIScrollView alloc]initWithFrame:self.view.bounds];
|
||||
[self.view addSubview:_wrapperView];
|
||||
|
||||
_pageScrollView = [[UIScrollView alloc]initWithFrame:self.view.bounds];
|
||||
_pageScrollView.clipsToBounds = true;
|
||||
_pageScrollView.opaque = true;
|
||||
@ -317,7 +321,7 @@ typedef enum {
|
||||
_pageScrollView.pagingEnabled = true;
|
||||
_pageScrollView.contentSize = CGSizeMake(_headlines.count * self.view.bounds.size.width, self.view.bounds.size.height);
|
||||
_pageScrollView.delegate = self;
|
||||
[self.view addSubview:_pageScrollView];
|
||||
[_wrapperView addSubview:_pageScrollView];
|
||||
|
||||
_pageViews = [NSMutableArray array];
|
||||
|
||||
@ -331,41 +335,6 @@ typedef enum {
|
||||
}
|
||||
[_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];
|
||||
|
||||
_pageControl = [[UIPageControl alloc] init];
|
||||
@ -374,7 +343,20 @@ typedef enum {
|
||||
[_pageControl setNumberOfPages:6];
|
||||
_pageControl.pageIndicatorTintColor = _regularDotColor;
|
||||
_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
|
||||
@ -527,12 +509,16 @@ typedef enum {
|
||||
_pageControl.frame = CGRectMake(0, pageControlY, self.view.bounds.size.width, 7);
|
||||
_glkView.frame = CGRectChangedOriginY(_glkView.frame, glViewY - statusBarHeight);
|
||||
|
||||
[_startButton sizeToFit];
|
||||
_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);
|
||||
[_startButton addTarget:self action:@selector(startButtonPress) forControlEvents:UIControlEventTouchUpInside];
|
||||
CGFloat startButtonWidth = self.view.bounds.size.width - 48.0f;
|
||||
UIView *startButton = self.createStartButton(startButtonWidth);
|
||||
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.contentSize=CGSizeMake(_headlines.count * self.view.bounds.size.width, 150);
|
||||
_pageScrollView.contentOffset = CGPointMake(_currentPage * self.view.bounds.size.width, 0);
|
||||
@ -691,7 +677,6 @@ NSInteger _current_page_end;
|
||||
- (void)setIsEnabled:(bool)isEnabled {
|
||||
if (_isEnabled != isEnabled) {
|
||||
_isEnabled = isEnabled;
|
||||
_startButton.alpha = _isEnabled ? 1.0 : 0.6;
|
||||
_alternativeLanguageButton.alpha = _isEnabled ? 1.0 : 0.6;
|
||||
}
|
||||
}
|
||||
|
@ -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] = []
|
||||
|
||||
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 {
|
||||
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 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))
|
||||
} |> afterDisposed {
|
||||
|
@ -263,7 +263,7 @@ public final class SolidRoundedButtonNode: ASDisplayNode {
|
||||
|
||||
self.setupGloss()
|
||||
}
|
||||
|
||||
|
||||
private func setupGloss() {
|
||||
if self.gloss {
|
||||
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() {
|
||||
guard let buttonBackgroundAnimationView = self.buttonBackgroundAnimationView else {
|
||||
return
|
||||
|
@ -1,232 +1,235 @@
|
||||
1876;JM;Jamaica
|
||||
1869;KN;Saint Kitts & Nevis
|
||||
1868;TT;Trinidad & Tobago
|
||||
1784;VC;Saint Vincent & the Grenadines
|
||||
1767;DM;Dominica
|
||||
1758;LC;Saint Lucia
|
||||
1721;SX;Sint Maarten
|
||||
1684;AS;American Samoa
|
||||
1671;GU;Guam
|
||||
1670;MP;Northern Mariana Islands
|
||||
1664;MS;Montserrat
|
||||
1649;TC;Turks & Caicos Islands
|
||||
1473;GD;Grenada
|
||||
1441;BM;Bermuda
|
||||
1345;KY;Cayman Islands
|
||||
1340;VI;US Virgin Islands
|
||||
1284;VG;British Virgin Islands
|
||||
1268;AG;Antigua & Barbuda
|
||||
1264;AI;Anguilla
|
||||
1246;BB;Barbados
|
||||
1242;BS;Bahamas
|
||||
998;UZ;Uzbekistan
|
||||
996;KG;Kyrgyzstan
|
||||
995;GE;Georgia
|
||||
994;AZ;Azerbaijan
|
||||
993;TM;Turkmenistan
|
||||
992;TJ;Tajikistan
|
||||
977;NP;Nepal
|
||||
976;MN;Mongolia
|
||||
975;BT;Bhutan
|
||||
974;QA;Qatar
|
||||
973;BH;Bahrain
|
||||
972;IL;Israel
|
||||
971;AE;United Arab Emirates
|
||||
970;PS;Palestine
|
||||
968;OM;Oman
|
||||
967;YE;Yemen
|
||||
966;SA;Saudi Arabia
|
||||
965;KW;Kuwait
|
||||
964;IQ;Iraq
|
||||
963;SY;Syrian Arab Republic
|
||||
962;JO;Jordan
|
||||
961;LB;Lebanon
|
||||
960;MV;Maldives
|
||||
886;TW;Taiwan
|
||||
880;BD;Bangladesh
|
||||
856;LA;Laos
|
||||
855;KH;Cambodia
|
||||
853;MO;Macau
|
||||
852;HK;Hong Kong
|
||||
850;KP;North Korea
|
||||
692;MH;Marshall Islands
|
||||
691;FM;Micronesia
|
||||
690;TK;Tokelau
|
||||
689;PF;French Polynesia
|
||||
688;TV;Tuvalu
|
||||
687;NC;New Caledonia
|
||||
686;KI;Kiribati
|
||||
685;WS;Samoa
|
||||
683;NU;Niue
|
||||
682;CK;Cook Islands
|
||||
681;WF;Wallis & Futuna
|
||||
680;PW;Palau
|
||||
679;FJ;Fiji
|
||||
678;VU;Vanuatu
|
||||
677;SB;Solomon Islands
|
||||
676;TO;Tonga
|
||||
675;PG;Papua New Guinea
|
||||
674;NR;Nauru
|
||||
673;BN;Brunei Darussalam
|
||||
672;NF;Norfolk Island
|
||||
670;TL;Timor-Leste
|
||||
599;BQ;Bonaire, Sint Eustatius & Saba
|
||||
599;CW;Curaçao
|
||||
598;UY;Uruguay
|
||||
597;SR;Suriname
|
||||
596;MQ;Martinique
|
||||
595;PY;Paraguay
|
||||
594;GF;French Guiana
|
||||
593;EC;Ecuador
|
||||
592;GY;Guyana
|
||||
591;BO;Bolivia
|
||||
590;GP;Guadeloupe
|
||||
509;HT;Haiti
|
||||
508;PM;Saint Pierre & Miquelon
|
||||
507;PA;Panama
|
||||
506;CR;Costa Rica
|
||||
505;NI;Nicaragua
|
||||
504;HN;Honduras
|
||||
503;SV;El Salvador
|
||||
502;GT;Guatemala
|
||||
501;BZ;Belize
|
||||
500;FK;Falkland Islands
|
||||
423;LI;Liechtenstein
|
||||
421;SK;Slovakia
|
||||
420;CZ;Czech Republic
|
||||
383;XK;Kosovo
|
||||
389;MK;Macedonia
|
||||
387;BA;Bosnia & Herzegovina
|
||||
386;SI;Slovenia
|
||||
385;HR;Croatia
|
||||
382;ME;Montenegro
|
||||
381;RS;Serbia
|
||||
380;UA;Ukraine
|
||||
378;SM;San Marino
|
||||
377;MC;Monaco
|
||||
376;AD;Andorra
|
||||
375;BY;Belarus
|
||||
374;AM;Armenia
|
||||
373;MD;Moldova
|
||||
372;EE;Estonia
|
||||
371;LV;Latvia
|
||||
370;LT;Lithuania
|
||||
359;BG;Bulgaria
|
||||
358;FI;Finland
|
||||
357;CY;Cyprus
|
||||
356;MT;Malta
|
||||
355;AL;Albania
|
||||
354;IS;Iceland
|
||||
353;IE;Ireland
|
||||
352;LU;Luxembourg
|
||||
351;PT;Portugal
|
||||
350;GI;Gibraltar
|
||||
299;GL;Greenland
|
||||
298;FO;Faroe Islands
|
||||
297;AW;Aruba
|
||||
291;ER;Eritrea
|
||||
290;SH;Saint Helena
|
||||
269;KM;Comoros
|
||||
268;SZ;Swaziland
|
||||
267;BW;Botswana
|
||||
266;LS;Lesotho
|
||||
265;MW;Malawi
|
||||
264;NA;Namibia
|
||||
263;ZW;Zimbabwe
|
||||
262;RE;Réunion
|
||||
261;MG;Madagascar
|
||||
260;ZM;Zambia
|
||||
258;MZ;Mozambique
|
||||
257;BI;Burundi
|
||||
256;UG;Uganda
|
||||
255;TZ;Tanzania
|
||||
254;KE;Kenya
|
||||
253;DJ;Djibouti
|
||||
252;SO;Somalia
|
||||
251;ET;Ethiopia
|
||||
250;RW;Rwanda
|
||||
249;SD;Sudan
|
||||
248;SC;Seychelles
|
||||
247;SH;Saint Helena
|
||||
246;IO;Diego Garcia
|
||||
245;GW;Guinea-Bissau
|
||||
244;AO;Angola
|
||||
243;CD;Congo (Dem. Rep.)
|
||||
242;CG;Congo (Rep.)
|
||||
241;GA;Gabon
|
||||
240;GQ;Equatorial Guinea
|
||||
239;ST;São Tomé & Príncipe
|
||||
238;CV;Cape Verde
|
||||
237;CM;Cameroon
|
||||
236;CF;Central African Rep.
|
||||
235;TD;Chad
|
||||
234;NG;Nigeria
|
||||
233;GH;Ghana
|
||||
232;SL;Sierra Leone
|
||||
231;LR;Liberia
|
||||
230;MU;Mauritius
|
||||
229;BJ;Benin
|
||||
228;TG;Togo
|
||||
227;NE;Niger
|
||||
226;BF;Burkina Faso
|
||||
225;CI;Côte d`Ivoire
|
||||
224;GN;Guinea
|
||||
223;ML;Mali
|
||||
222;MR;Mauritania
|
||||
221;SN;Senegal
|
||||
220;GM;Gambia
|
||||
218;LY;Libya
|
||||
216;TN;Tunisia
|
||||
213;DZ;Algeria
|
||||
212;MA;Morocco
|
||||
211;SS;South Sudan
|
||||
98;IR;Iran
|
||||
95;MM;Myanmar
|
||||
94;LK;Sri Lanka
|
||||
93;AF;Afghanistan
|
||||
92;PK;Pakistan
|
||||
91;IN;India
|
||||
90;TR;Turkey
|
||||
86;CN;China
|
||||
84;VN;Vietnam
|
||||
82;KR;South Korea
|
||||
81;JP;Japan
|
||||
66;TH;Thailand
|
||||
65;SG;Singapore
|
||||
64;NZ;New Zealand
|
||||
63;PH;Philippines
|
||||
62;ID;Indonesia
|
||||
61;AU;Australia
|
||||
60;MY;Malaysia
|
||||
58;VE;Venezuela
|
||||
57;CO;Colombia
|
||||
56;CL;Chile
|
||||
55;BR;Brazil
|
||||
54;AR;Argentina
|
||||
53;CU;Cuba
|
||||
52;MX;Mexico
|
||||
51;PE;Peru
|
||||
49;DE;Germany
|
||||
48;PL;Poland
|
||||
47;NO;Norway
|
||||
46;SE;Sweden
|
||||
45;DK;Denmark
|
||||
44;GB;United Kingdom
|
||||
43;AT;Austria
|
||||
41;CH;Switzerland
|
||||
40;RO;Romania
|
||||
39;IT;Italy
|
||||
36;HU;Hungary
|
||||
34;ES;Spain
|
||||
33;FR;France
|
||||
32;BE;Belgium
|
||||
31;NL;Netherlands
|
||||
30;GR;Greece
|
||||
27;ZA;South Africa
|
||||
20;EG;Egypt
|
||||
7;RU;Russian Federation
|
||||
7;KZ;Kazakhstan
|
||||
1;US;USA
|
||||
1;PR;Puerto Rico
|
||||
1;DO;Dominican Rep.
|
||||
1;CA;Canada
|
||||
376;AD;XX XX XX;Andorra
|
||||
971;AE;XX XXX XXXX;United Arab Emirates
|
||||
93;AF;XXX XXX XXX;Afghanistan
|
||||
1268;AG;XXX XXXX;Antigua & Barbuda
|
||||
1264;AI;XXX XXXX;Anguilla
|
||||
355;AL;XX XXX XXXX;Albania
|
||||
374;AM;XX XXX XXX;Armenia
|
||||
244;AO;XXX XXX XXX;Angola
|
||||
54;AR;;Argentina
|
||||
1684;AS;XXX XXXX;American Samoa
|
||||
43;AT;XXX XXXXXX;Austria
|
||||
61;AU;X XXXX XXXX;Australia
|
||||
297;AW;XXX XXXX;Aruba
|
||||
994;AZ;XX XXX XXXX;Azerbaijan
|
||||
387;BA;XX XXX XXX;Bosnia & Herzegovina
|
||||
1246;BB;XXX XXXX;Barbados
|
||||
880;BD;XX XXX XXX;Bangladesh
|
||||
32;BE;XXX XX XX XX;Belgium
|
||||
226;BF;XX XX XX XX;Burkina Faso
|
||||
359;BG;;Bulgaria
|
||||
973;BH;XXXX XXXX;Bahrain
|
||||
257;BI;XX XX XXXX;Burundi
|
||||
229;BJ;XX XXX XXX;Benin
|
||||
1441;BM;XXX XXXX;Bermuda
|
||||
673;BN;XXX XXXX;Brunei Darussalam
|
||||
591;BO;X XXX XXXX;Bolivia
|
||||
599;BQ;;Bonaire, Sint Eustatius & Saba
|
||||
55;BR;XX XXXXX XXXX;Brazil
|
||||
1242;BS;XXX XXXX;Bahamas
|
||||
975;BT;XX XXX XXX;Bhutan
|
||||
267;BW;XX XXX XXX;Botswana
|
||||
375;BY;XX XXX XXXX;Belarus
|
||||
501;BZ;;Belize
|
||||
1;US;XXX XXX XXXX;United States
|
||||
1;CA;XXX XXX XXXX;Canada
|
||||
243;CD;XX XXX XXXX;Congo (Dem. Rep.)
|
||||
236;CF;XX XX XX XX;Central African Rep.
|
||||
242;CG;XX XXX XXXX;Congo (Rep.)
|
||||
41;CH;XX XXX XXXX;Switzerland
|
||||
225;CI;XX XX XX XXXX;Côte d'Ivoire
|
||||
682;CK;;Cook Islands
|
||||
56;CL;X XXXX XXXX;Chile
|
||||
237;CM;XXXX XXXX;Cameroon
|
||||
86;CN;XXX XXXX XXXX;China
|
||||
57;CO;XXX XXX XXXX;Colombia
|
||||
506;CR;XXXX XXXX;Costa Rica
|
||||
53;CU;X XXX XXXX;Cuba
|
||||
238;CV;XXX XXXX;Cape Verde
|
||||
599;CW;;Curaçao
|
||||
357;CY;XXXX XXXX;Cyprus
|
||||
420;CZ;XXX XXX XXX;Czech Republic
|
||||
49;DE;;Germany
|
||||
253;DJ;XX XX XX XX;Djibouti
|
||||
45;DK;XXXX XXXX;Denmark
|
||||
1767;DM;XXX XXXX;Dominica
|
||||
1809;DO;XXX XXXX;Dominican Rep.
|
||||
1829;DO;XXX XXXX;Dominican Rep.
|
||||
1849;DO;XXX XXXX;Dominican Rep.
|
||||
213;DZ;XXX XX XX XX;Algeria
|
||||
593;EC;XX XXX XXXX;Ecuador
|
||||
372;EE;XXXX XXX;Estonia
|
||||
20;EG;XX XXXX XXXX;Egypt
|
||||
291;ER;X XXX XXX;Eritrea
|
||||
34;ES;XXX XXX XXX;Spain
|
||||
251;ET;XX XXX XXX;Ethiopia
|
||||
358;FI;;Finland
|
||||
679;FJ;XXX XXXX;Fiji
|
||||
500;FK;;Falkland Islands
|
||||
691;FM;;Micronesia
|
||||
298;FO;XXX XXX;Faroe Islands
|
||||
33;FR;X XX XX XX XX;France
|
||||
241;GA;X XX XX XX;Gabon
|
||||
44;GB;XXXX XXXXXX;United Kingdom
|
||||
1473;GD;XXX XXXX;Grenada
|
||||
995;GE;XXX XXX XXX;Georgia
|
||||
594;GF;;French Guiana
|
||||
233;GH;XX XXX XXXX;Ghana
|
||||
350;GI;XXXX XXXX;Gibraltar
|
||||
299;GL;XXX XXX;Greenland
|
||||
220;GM;XXX XXXX;Gambia
|
||||
224;GN;XXX XXX XXX;Guinea
|
||||
590;GP;XXX XX XX XX;Guadeloupe
|
||||
240;GQ;XXX XXX XXX;Equatorial Guinea
|
||||
30;GR;XXX XXX XXXX;Greece
|
||||
502;GT;X XXX XXXX;Guatemala
|
||||
1671;GU;XXX XXXX;Guam
|
||||
245;GW;XXX XXXX;Guinea-Bissau
|
||||
592;GY;;Guyana
|
||||
852;HK;X XXX XXXX;Hong Kong
|
||||
504;HN;XXXX XXXX;Honduras
|
||||
385;HR;XX XXX XXX;Croatia
|
||||
509;HT;XXXX XXXX;Haiti
|
||||
36;HU;XXX XXX XXX;Hungary
|
||||
62;ID;XXX XXXXXX;Indonesia
|
||||
353;IE;XX XXX XXXX;Ireland
|
||||
972;IL;XX XXX XXXX;Israel
|
||||
91;IN;XXXXX XXXXX;India
|
||||
246;IO;XXX XXXX;Diego Garcia
|
||||
964;IQ;XXX XXX XXXX;Iraq
|
||||
98;IR;XXX XXX XXXX;Iran
|
||||
354;IS;XXX XXXX;Iceland
|
||||
39;IT;XXX XXX XXXX;Italy
|
||||
1876;JM;XXX XXXX;Jamaica
|
||||
962;JO;X XXXX XXXX;Jordan
|
||||
81;JP;XX XXXX XXXX;Japan
|
||||
254;KE;XXX XXX XXX;Kenya
|
||||
996;KG;XXX XXXXXX;Kyrgyzstan
|
||||
855;KH;XX XXX XXX;Cambodia
|
||||
686;KI;XXXX XXXX;Kiribati
|
||||
269;KM;XXX XXXX;Comoros
|
||||
1869;KN;XXX XXXX;Saint Kitts & Nevis
|
||||
850;KP;;North Korea
|
||||
82;KR;XX XXXX XXX;South Korea
|
||||
965;KW;XXXX XXXX;Kuwait
|
||||
1345;KY;XXX XXXX;Cayman Islands
|
||||
7;RU;XXX XXX XXXX;Russian Federation
|
||||
7;KZ;XXX XXX XX XX;Kazakhstan
|
||||
856;LA;XX XX XXX XXX;Laos
|
||||
961;LB;;Lebanon
|
||||
1758;LC;XXX XXXX;Saint Lucia
|
||||
423;LI;XXX XXXX;Liechtenstein
|
||||
94;LK;XX XXX XXXX;Sri Lanka
|
||||
231;LR;XX XXX XXXX;Liberia
|
||||
266;LS;XX XXX XXX;Lesotho
|
||||
370;LT;XXX XXXXX;Lithuania
|
||||
352;LU;XXX XXX XXX;Luxembourg
|
||||
371;LV;XXX XXXXX;Latvia
|
||||
218;LY;XX XXX XXXX;Libya
|
||||
212;MA;XX XXX XXXX;Morocco
|
||||
377;MC;XXXX XXXX;Monaco
|
||||
373;MD;XX XXX XXX;Moldova
|
||||
382;ME;;Montenegro
|
||||
261;MG;XX XX XXX XX;Madagascar
|
||||
692;MH;;Marshall Islands
|
||||
389;MK;XX XXXXXX;North Macedonia
|
||||
223;ML;XXXX XXXX;Mali
|
||||
95;MM;;Myanmar
|
||||
976;MN;XX XX XXXX;Mongolia
|
||||
853;MO;XXXX XXXX;Macau
|
||||
1670;MP;XXX XXXX;Northern Mariana Islands
|
||||
596;MQ;;Martinique
|
||||
222;MR;XXXX XXXX;Mauritania
|
||||
1664;MS;XXX XXXX;Montserrat
|
||||
356;MT;XX XX XX XX;Malta
|
||||
230;MU;XXXX XXXX;Mauritius
|
||||
960;MV;XXX XXXX;Maldives
|
||||
265;MW;XX XXX XXXX;Malawi
|
||||
52;MX;;Mexico
|
||||
60;MY;;Malaysia
|
||||
258;MZ;XX XXX XXXX;Mozambique
|
||||
264;NA;XX XXX XXXX;Namibia
|
||||
687;NC;;New Caledonia
|
||||
227;NE;XX XX XX XX;Niger
|
||||
672;NF;;Norfolk Island
|
||||
234;NG;XX XXXX XXXX;Nigeria
|
||||
505;NI;XXXX XXXX;Nicaragua
|
||||
31;NL;X XX XX XX XX;Netherlands
|
||||
47;NO;XXX XX XXX;Norway
|
||||
977;NP;XX XXXX XXXX;Nepal
|
||||
674;NR;;Nauru
|
||||
683;NU;;Niue
|
||||
64;NZ;XXXX XXXX;New Zealand
|
||||
968;OM;XXXX XXXX;Oman
|
||||
507;PA;XXXX XXXX;Panama
|
||||
51;PE;XXX XXX XXX;Peru
|
||||
689;PF;;French Polynesia
|
||||
675;PG;;Papua New Guinea
|
||||
63;PH;XXX XXX XXXX;Philippines
|
||||
92;PK;XXX XXX XXXX;Pakistan
|
||||
48;PL;XXX XXX XXX;Poland
|
||||
508;PM;;Saint Pierre & Miquelon
|
||||
1787;PR;XXX XXXX;Puerto Rico
|
||||
1939;PR;XXX XXXX;Puerto Rico
|
||||
970;PS;XXX XX XXXX;Palestine
|
||||
351;PT;XXX XXX XXX;Portugal
|
||||
680;PW;;Palau
|
||||
595;PY;XXX XXX XXX;Paraguay
|
||||
974;QA;XX XXX XXX;Qatar
|
||||
262;RE;XXX XXX XXX;Réunion
|
||||
40;RO;XXX XXX XXX;Romania
|
||||
381;RS;XX XXX XXX;Serbia
|
||||
250;RW;XXX XXX XXX;Rwanda
|
||||
966;SA;XX XXX XXXX;Saudi Arabia
|
||||
677;SB;;Solomon Islands
|
||||
248;SC;X XX XX XX;Seychelles
|
||||
249;SD;XX XXX XXXX;Sudan
|
||||
46;SE;XX XXX XXXX;Sweden
|
||||
65;SG;XXXX XXXX;Singapore
|
||||
247;SH;;Saint Helena
|
||||
290;SH;XX XXX;Saint Helena
|
||||
386;SI;XX XXX XXX;Slovenia
|
||||
421;SK;XXX XXX XXX;Slovakia
|
||||
232;SL;XX XXX XXX;Sierra Leone
|
||||
378;SM;;San Marino
|
||||
221;SN;XX XXX XXXX;Senegal
|
||||
252;SO;XX XXX XXX;Somalia
|
||||
597;SR;XXX XXXX;Suriname
|
||||
211;SS;XX XXX XXXX;South Sudan
|
||||
239;ST;XX XXXXX;São Tomé & Príncipe
|
||||
503;SV;XXXX XXXX;El Salvador
|
||||
1721;SX;XXX XXXX;Sint Maarten
|
||||
963;SY;XXX XXX XXX;Syria
|
||||
268;SZ;XXXX XXXX;Eswatini
|
||||
1649;TC;XXX XXXX;Turks & Caicos Islands
|
||||
235;TD;XX XX XX XX;Chad
|
||||
228;TG;XX XXX XXX;Togo
|
||||
66;TH;X XXXX XXXX;Thailand
|
||||
992;TJ;XX XXX XXXX;Tajikistan
|
||||
690;TK;;Tokelau
|
||||
670;TL;;Timor-Leste
|
||||
993;TM;XX XXXXXX;Turkmenistan
|
||||
216;TN;XX XXX XXX;Tunisia
|
||||
676;TO;;Tonga
|
||||
90;TR;XXX XXX XXXX;Turkey
|
||||
1868;TT;XXX XXXX;Trinidad & Tobago
|
||||
688;TV;;Tuvalu
|
||||
886;TW;XXX XXX XXX;Taiwan
|
||||
255;TZ;XX XXX XXXX;Tanzania
|
||||
380;UA;XX XXX XX XX;Ukraine
|
||||
256;UG;XX XXX XXXX;Uganda
|
||||
598;UY;X XXX XXXX;Uruguay
|
||||
998;UZ;XX XXX XX XX;Uzbekistan
|
||||
1784;VC;XXX XXXX;Saint Vincent & the Grenadines
|
||||
58;VE;XXX XXX XXXX;Venezuela
|
||||
1284;VG;XXX XXXX;British Virgin Islands
|
||||
1340;VI;XXX XXXX;US Virgin Islands
|
||||
84;VN;;Vietnam
|
||||
678;VU;;Vanuatu
|
||||
681;WF;;Wallis & Futuna
|
||||
685;WS;;Samoa
|
||||
383;XK;XXXX XXXX;Kosovo
|
||||
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
|
||||
|
@ -1105,8 +1105,10 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
||||
|> take(1)
|
||||
|> timeout(4.0, queue: .mainQueue(), alternate: .complete())
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
authContextValue.rootController.view.endEditing(true)
|
||||
authContextValue.rootController.dismiss()
|
||||
Queue.mainQueue().after(0.75) {
|
||||
authContextValue.rootController.view.endEditing(true)
|
||||
authContextValue.rootController.dismiss()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
authContextValue.rootController.view.endEditing(true)
|
||||
|
@ -115,6 +115,15 @@ final class AuthorizationSequenceCodeEntryController: ViewController {
|
||||
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)?) {
|
||||
self.termsOfService = termsOfService
|
||||
if self.data?.0 != number || self.data?.1 != codeType || self.data?.2 != nextType || self.data?.3 != timeout {
|
||||
|
@ -33,6 +33,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
private var signInWithAppleButton: UIControl?
|
||||
|
||||
private let codeInputView: CodeInputView
|
||||
private let errorTextNode: ImmediateTextNode
|
||||
|
||||
private var codeType: SentAuthorizationCodeType?
|
||||
|
||||
@ -69,7 +70,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
self.codeInputView.alpha = self.inProgress ? 0.6 : 1.0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
init(strings: PresentationStrings, theme: PresentationTheme) {
|
||||
self.strings = strings
|
||||
self.theme = theme
|
||||
@ -119,6 +120,11 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
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)
|
||||
|
||||
if #available(iOS 13.0, *) {
|
||||
@ -136,8 +142,6 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
self.backgroundColor = self.theme.list.plainBackgroundColor
|
||||
|
||||
self.addSubnode(self.codeInputView)
|
||||
//self.addSubnode(self.codeSeparatorNode)
|
||||
//self.addSubnode(self.codeField)
|
||||
self.addSubnode(self.titleNode)
|
||||
self.addSubnode(self.titleIconNode)
|
||||
self.addSubnode(self.currentOptionNode)
|
||||
@ -145,6 +149,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
self.addSubnode(self.nextOptionButtonNode)
|
||||
self.addSubnode(self.animationNode)
|
||||
self.addSubnode(self.dividerNode)
|
||||
self.addSubnode(self.errorTextNode)
|
||||
|
||||
self.codeInputView.updated = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
@ -208,7 +213,7 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
}
|
||||
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 {
|
||||
self.currentOptionInfoNode.attributedText = NSAttributedString(string: self.strings.Login_CodePhonePatternInfoText, font: Font.regular(17.0), textColor: self.theme.list.itemPrimaryTextColor, paragraphAlignment: .center)
|
||||
} else {
|
||||
@ -259,18 +264,18 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
var animationName = "IntroMessage"
|
||||
if let codeType = self.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:
|
||||
self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_EnterMissingDigits, font: Font.semibold(28.0), textColor: self.theme.list.itemPrimaryTextColor)
|
||||
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"
|
||||
case .sms:
|
||||
self.titleNode.attributedText = NSAttributedString(string: self.strings.Login_EnterCodeSMSTitle, font: Font.semibold(28.0), textColor: self.theme.list.itemPrimaryTextColor)
|
||||
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 {
|
||||
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 {
|
||||
@ -286,11 +291,11 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
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 currentOptionSize = self.currentOptionNode.updateLayout(CGSize(width: layout.size.width - 28.0, height: CGFloat.greatestFiniteMagnitude))
|
||||
let currentOptionInfoSize = self.currentOptionInfoNode.measure(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 - 48.0, height: CGFloat.greatestFiniteMagnitude))
|
||||
let nextOptionSize = self.nextOptionTitleNode.updateLayout(CGSize(width: layout.size.width, height: CGFloat.greatestFiniteMagnitude))
|
||||
|
||||
let codeLength: Int
|
||||
@ -323,6 +328,8 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
||||
theme: CodeInputView.Theme(
|
||||
inactiveBorder: self.theme.list.itemPlainSeparatorColor.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,
|
||||
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.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.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.codeInputView, size: codeFieldSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 30.0, maxValue: 30.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:
|
||||
@ -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.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.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.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() {
|
||||
let _ = self.codeInputView.becomeFirstResponder()
|
||||
//self.codeField.textField.becomeFirstResponder()
|
||||
}
|
||||
|
||||
func animateError() {
|
||||
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) {
|
||||
|
@ -68,7 +68,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
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), emptyAreaColor: .black), isFlat: true)
|
||||
|
||||
self.stateDisposable = (TelegramEngineUnauthorized(account: self.account).auth.state()
|
||||
|> map { state -> InnerState in
|
||||
@ -130,7 +130,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
return controller
|
||||
}
|
||||
|
||||
private func phoneEntryController(countryCode: Int32, number: String) -> AuthorizationSequencePhoneEntryController {
|
||||
private func phoneEntryController(countryCode: Int32, number: String, splashController: AuthorizationSequenceSplashController?) -> AuthorizationSequencePhoneEntryController {
|
||||
var currentController: AuthorizationSequencePhoneEntryController?
|
||||
for c in self.viewControllers {
|
||||
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()
|
||||
}
|
||||
})
|
||||
if let splahController = splashController {
|
||||
controller.animateWithSplashController(splahController)
|
||||
}
|
||||
controller.accountUpdated = { [weak self] updatedAccount in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
@ -393,35 +396,39 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
let _ = beginSignUp(account: strongSelf.account, data: data).start()
|
||||
}
|
||||
case .loggedIn:
|
||||
break
|
||||
controller?.animateSuccess()
|
||||
}
|
||||
}, error: { error in
|
||||
Queue.mainQueue().async {
|
||||
if let strongSelf = self, let controller = controller {
|
||||
controller.inProgress = false
|
||||
|
||||
var resetCode = false
|
||||
let text: String
|
||||
switch error {
|
||||
case .limitExceeded:
|
||||
resetCode = true
|
||||
text = strongSelf.presentationData.strings.Login_CodeFloodError
|
||||
case .invalidCode:
|
||||
resetCode = true
|
||||
text = strongSelf.presentationData.strings.Login_InvalidCodeError
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
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 case .invalidCode = error {
|
||||
controller.animateError(text: strongSelf.presentationData.strings.Login_WrongCodeError)
|
||||
} else {
|
||||
var resetCode = false
|
||||
let text: String
|
||||
switch error {
|
||||
case .limitExceeded:
|
||||
resetCode = true
|
||||
text = strongSelf.presentationData.strings.Login_CodeFloodError
|
||||
case .invalidCode:
|
||||
resetCode = true
|
||||
text = strongSelf.presentationData.strings.Login_InvalidCodeError
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Login_UnknownError
|
||||
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 {
|
||||
controllers.append(self.splashController())
|
||||
} else {
|
||||
controllers.append(self.phoneEntryController(countryCode: defaultCountryCode(), number: ""))
|
||||
controllers.append(self.phoneEntryController(countryCode: defaultCountryCode(), number: "", splashController: nil))
|
||||
}
|
||||
self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty)
|
||||
}
|
||||
@ -994,14 +1001,21 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
|
||||
if !self.otherAccountPhoneNumbers.1.isEmpty {
|
||||
controllers.append(self.splashController())
|
||||
}
|
||||
controllers.append(self.phoneEntryController(countryCode: countryCode, number: number))
|
||||
self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty)
|
||||
var previousSplashController: AuthorizationSequenceSplashController?
|
||||
for c in self.viewControllers {
|
||||
if let c = c as? AuthorizationSequenceSplashController {
|
||||
previousSplashController = c
|
||||
break
|
||||
}
|
||||
}
|
||||
controllers.append(self.phoneEntryController(countryCode: countryCode, number: number, splashController: previousSplashController))
|
||||
self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty && (previousSplashController == nil || self.viewControllers.count > 2))
|
||||
case let .confirmationCodeEntry(number, type, _, timeout, nextType, _):
|
||||
var controllers: [ViewController] = []
|
||||
if !self.otherAccountPhoneNumbers.1.isEmpty {
|
||||
controllers.append(self.splashController())
|
||||
}
|
||||
controllers.append(self.phoneEntryController(countryCode: defaultCountryCode(), number: ""))
|
||||
controllers.append(self.phoneEntryController(countryCode: defaultCountryCode(), number: "", splashController: nil))
|
||||
if case let .emailSetupRequired(appleSignInAllowed) = type {
|
||||
controllers.append(self.emailSetupController(number: number, appleSignInAllowed: appleSignInAllowed))
|
||||
} else {
|
||||
|
@ -17,7 +17,7 @@ final class AuthorizationDividerNode: ASDisplayNode {
|
||||
init(theme: PresentationTheme, strings: PresentationStrings) {
|
||||
self.titleNode = ImmediateTextNode()
|
||||
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.backgroundColor = theme.list.itemSecondaryTextColor
|
||||
@ -90,20 +90,20 @@ final class AuthorizationSequenceEmailEntryControllerNode: ASDisplayNode, UIText
|
||||
self.titleNode = ASTextNode()
|
||||
self.titleNode.isUserInteractionEnabled = 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.isUserInteractionEnabled = false
|
||||
self.noticeNode.displaysAsynchronously = false
|
||||
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, *) {
|
||||
self.signInWithAppleButton = ASAuthorizationAppleIDButton(authorizationButtonType: .signIn, authorizationButtonStyle: theme.overallDarkAppearance ? .white : .black)
|
||||
(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.isLayerBacked = true
|
||||
@ -120,7 +120,7 @@ final class AuthorizationSequenceEmailEntryControllerNode: ASDisplayNode, UIText
|
||||
self.codeField.textField.keyboardAppearance = self.theme.rootController.keyboardColor.keyboardAppearance
|
||||
self.codeField.textField.disableAutomaticKeyboardHandling = [.forward, .backward]
|
||||
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)
|
||||
|
||||
@ -193,9 +193,9 @@ final class AuthorizationSequenceEmailEntryControllerNode: ASDisplayNode, UIText
|
||||
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 noticeSize = self.noticeNode.measure(CGSize(width: layout.size.width - 80.0, height: CGFloat.greatestFiniteMagnitude))
|
||||
|
@ -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() {
|
||||
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 {
|
||||
@ -146,22 +157,42 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
|
||||
})
|
||||
}
|
||||
|
||||
private var animatingIn = false
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
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) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
self.controllerNode.activateInput()
|
||||
if !self.animatingIn {
|
||||
self.controllerNode.activateInput()
|
||||
}
|
||||
}
|
||||
|
||||
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, 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() {
|
||||
|
@ -154,12 +154,18 @@ private final class PhoneAndCountryNode: ASDisplayNode {
|
||||
let flagString = emojiFlagForISOCountryCode(name)
|
||||
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.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] {
|
||||
let flagString = emojiFlagForISOCountryCode(countryId)
|
||||
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.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 {
|
||||
strongSelf.countryButton.setTitle(strings.Login_SelectCountry, with: Font.regular(20.0), with: theme.list.itemAccentColor, for: [])
|
||||
strongSelf.phoneInputNode.mask = nil
|
||||
@ -330,7 +336,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
|
||||
|
||||
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
|
||||
|
||||
super.init()
|
||||
@ -380,6 +386,64 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
|
||||
#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() {
|
||||
self.phoneAndCountryNode.phoneInputNode.codeAndNumber = self.codeAndNumber
|
||||
}
|
||||
@ -396,7 +460,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
|
||||
|
||||
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 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)
|
||||
@ -411,12 +475,19 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
|
||||
let contactSyncSize = self.contactSyncNode.updateLayout(width: layout.size.width)
|
||||
if self.hasOtherAccounts {
|
||||
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 {
|
||||
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)
|
||||
|
||||
|
@ -141,7 +141,7 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel
|
||||
self.addPhotoButton.addSubnode(self.currentPhotoNode)
|
||||
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()
|
||||
|
||||
|
@ -7,7 +7,7 @@ import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import LegacyComponents
|
||||
|
||||
import SolidRoundedButtonNode
|
||||
import RMIntro
|
||||
|
||||
final class AuthorizationSequenceSplashController: ViewController {
|
||||
@ -28,6 +28,8 @@ final class AuthorizationSequenceSplashController: ViewController {
|
||||
private let suggestedLocalization = Promise<SuggestedLocalizationInfo?>()
|
||||
private let activateLocalizationDisposable = MetaDisposable()
|
||||
|
||||
private let startButton: SolidRoundedButtonNode
|
||||
|
||||
init(accountManager: AccountManager<TelegramAccountManagerTypes>, account: UnauthorizedAccount, theme: PresentationTheme) {
|
||||
self.accountManager = accountManager
|
||||
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)
|
||||
|
||||
@ -84,6 +88,15 @@ final class AuthorizationSequenceSplashController: ViewController {
|
||||
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) {
|
||||
@ -99,20 +112,32 @@ final class AuthorizationSequenceSplashController: ViewController {
|
||||
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() {
|
||||
if !controller.isViewLoaded || controller.view.superview == nil {
|
||||
self.displayNode.view.addSubview(controller.view)
|
||||
if !self.controller.isViewLoaded || self.controller.view.superview == nil {
|
||||
self.displayNode.view.addSubview(self.controller.view)
|
||||
if let layout = self.validLayout {
|
||||
controller.view.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
}
|
||||
controller.viewDidAppear(false)
|
||||
self.controller.viewDidAppear(false)
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.addControllerIfNeeded()
|
||||
controller.viewWillAppear(false)
|
||||
self.controller.viewWillAppear(false)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
@ -182,6 +207,7 @@ final class AuthorizationSequenceSplashController: ViewController {
|
||||
}
|
||||
|
||||
strongSelf.controller.isEnabled = false
|
||||
strongSelf.startButton.alpha = 0.6
|
||||
let accountManager = strongSelf.accountManager
|
||||
|
||||
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
|
||||
self?.controller.isEnabled = true
|
||||
self?.startButton.alpha = 1.0
|
||||
self?.pressNext(strings: strings)
|
||||
})
|
||||
}))
|
||||
|
Loading…
x
Reference in New Issue
Block a user