Merge commit 'b8a7ca4de1ace9e5f1d097349aa9c8fba2b136e3'

This commit is contained in:
Ali 2022-11-27 22:10:47 +04:00
commit a90d128527
12 changed files with 453 additions and 423 deletions

View File

@ -8335,3 +8335,5 @@ Sorry for the inconvenience.";
"UserInfo.AnonymousNumberLabel" = "anonymous number"; "UserInfo.AnonymousNumberLabel" = "anonymous number";
"UserInfo.AnonymousNumberInfo" = "This number is not tied to a SIM card and was acquired on [Fragment]()."; "UserInfo.AnonymousNumberInfo" = "This number is not tied to a SIM card and was acquired on [Fragment]().";
"Login.NewNumber" = "New Number";

View File

@ -15,7 +15,6 @@ public final class AuthorizationSequenceCodeEntryController: ViewController {
private let strings: PresentationStrings private let strings: PresentationStrings
private let theme: PresentationTheme private let theme: PresentationTheme
private let openUrl: (String) -> Void
public var loginWithCode: ((String) -> Void)? public var loginWithCode: ((String) -> Void)?
public var signInWithApple: (() -> Void)? public var signInWithApple: (() -> Void)?
@ -38,10 +37,9 @@ public final class AuthorizationSequenceCodeEntryController: ViewController {
} }
} }
public init(presentationData: PresentationData, openUrl: @escaping (String) -> Void, back: @escaping () -> Void) { public init(presentationData: PresentationData, back: @escaping () -> Void) {
self.strings = presentationData.strings self.strings = presentationData.strings
self.theme = presentationData.theme self.theme = presentationData.theme
self.openUrl = openUrl
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: AuthorizationSequenceController.navigationBarTheme(theme), strings: NavigationBarStrings(presentationStrings: strings))) super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: AuthorizationSequenceController.navigationBarTheme(theme), strings: NavigationBarStrings(presentationStrings: strings)))
@ -217,7 +215,7 @@ public final class AuthorizationSequenceCodeEntryController: ViewController {
self.loginWithCode?(code) self.loginWithCode?(code)
} }
func applyConfirmationCode(_ code: Int) { public func applyConfirmationCode(_ code: Int) {
self.controllerNode.updateCode("\(code)") self.controllerNode.updateCode("\(code)")
} }
} }

View File

@ -120,7 +120,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
let masterDatacenterId = strongSelf.account.masterDatacenterId let masterDatacenterId = strongSelf.account.masterDatacenterId
let isTestingEnvironment = strongSelf.account.testingEnvironment let isTestingEnvironment = strongSelf.account.testingEnvironment
let countryCode = defaultCountryCode() let countryCode = AuthorizationSequenceController.defaultCountryCode()
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: isTestingEnvironment, masterDatacenterId: masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start() let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: isTestingEnvironment, masterDatacenterId: masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start()
} }
@ -275,13 +275,11 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
if let currentController = currentController { if let currentController = currentController {
controller = currentController controller = currentController
} else { } else {
controller = AuthorizationSequenceCodeEntryController(presentationData: self.presentationData, openUrl: { [weak self] url in controller = AuthorizationSequenceCodeEntryController(presentationData: self.presentationData, back: { [weak self] in
self?.openUrl(url)
}, back: { [weak self] in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
let countryCode = defaultCountryCode() let countryCode = AuthorizationSequenceController.defaultCountryCode()
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start() let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start()
}) })
@ -542,7 +540,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
let countryCode = defaultCountryCode() let countryCode = AuthorizationSequenceController.defaultCountryCode()
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start() let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start()
}) })
@ -707,7 +705,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
let countryCode = defaultCountryCode() let countryCode = AuthorizationSequenceController.defaultCountryCode()
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start() let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start()
}) })
@ -852,7 +850,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
let countryCode = defaultCountryCode() let countryCode = AuthorizationSequenceController.defaultCountryCode()
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start() let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start()
}) })
@ -912,7 +910,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
let countryCode = defaultCountryCode() let countryCode = AuthorizationSequenceController.defaultCountryCode()
let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start() let _ = TelegramEngineUnauthorized(account: strongSelf.account).auth.setState(state: UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .phoneEntry(countryCode: countryCode, number: ""))).start()
}, displayCancel: displayCancel) }, displayCancel: displayCancel)
@ -1022,7 +1020,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
if self.otherAccountPhoneNumbers.1.isEmpty { if self.otherAccountPhoneNumbers.1.isEmpty {
controllers.append(self.splashController()) controllers.append(self.splashController())
} else { } else {
controllers.append(self.phoneEntryController(countryCode: defaultCountryCode(), number: "", splashController: nil)) controllers.append(self.phoneEntryController(countryCode: AuthorizationSequenceController.defaultCountryCode(), number: "", splashController: nil))
} }
self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty) self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty)
} }
@ -1050,7 +1048,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
if !self.otherAccountPhoneNumbers.1.isEmpty { if !self.otherAccountPhoneNumbers.1.isEmpty {
controllers.append(self.splashController()) controllers.append(self.splashController())
} }
controllers.append(self.phoneEntryController(countryCode: defaultCountryCode(), number: "", splashController: nil)) controllers.append(self.phoneEntryController(countryCode: AuthorizationSequenceController.defaultCountryCode(), number: "", splashController: nil))
if case let .emailSetupRequired(appleSignInAllowed) = type { if case let .emailSetupRequired(appleSignInAllowed) = type {
self.appleSignInAllowed = appleSignInAllowed self.appleSignInAllowed = appleSignInAllowed
controllers.append(self.emailSetupController(number: number, appleSignInAllowed: appleSignInAllowed)) controllers.append(self.emailSetupController(number: number, appleSignInAllowed: appleSignInAllowed))
@ -1156,30 +1154,30 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
self?.presentingViewController?.dismiss(animated: false, completion: nil) self?.presentingViewController?.dismiss(animated: false, completion: nil)
}) })
} }
}
private func defaultCountryCode() -> Int32 {
var countryId: String? = nil
let networkInfo = CTTelephonyNetworkInfo()
if let carrier = networkInfo.subscriberCellularProvider {
countryId = carrier.isoCountryCode
}
if countryId == nil { public static func defaultCountryCode() -> Int32 {
countryId = (Locale.current as NSLocale).object(forKey: .countryCode) as? String var countryId: String? = nil
} let networkInfo = CTTelephonyNetworkInfo()
if let carrier = networkInfo.subscriberCellularProvider {
var countryCode: Int32 = 1 countryId = carrier.isoCountryCode
}
if let countryId = countryId {
let normalizedId = countryId.uppercased() if countryId == nil {
for (code, idAndName) in countryCodeToIdAndName { countryId = (Locale.current as NSLocale).object(forKey: .countryCode) as? String
if idAndName.0 == normalizedId { }
countryCode = Int32(code)
break var countryCode: Int32 = 1
if let countryId = countryId {
let normalizedId = countryId.uppercased()
for (code, idAndName) in countryCodeToIdAndName {
if idAndName.0 == normalizedId {
countryCode = Int32(code)
break
}
} }
} }
return countryCode
} }
return countryCode
} }

View File

@ -11,8 +11,9 @@ import AccountContext
import CountrySelectionUI import CountrySelectionUI
import PhoneNumberFormat import PhoneNumberFormat
import DebugSettingsUI import DebugSettingsUI
import MessageUI
final class AuthorizationSequencePhoneEntryController: ViewController { public final class AuthorizationSequencePhoneEntryController: ViewController, MFMailComposeViewControllerDelegate {
private var controllerNode: AuthorizationSequencePhoneEntryControllerNode { private var controllerNode: AuthorizationSequencePhoneEntryControllerNode {
return self.displayNode as! AuthorizationSequencePhoneEntryControllerNode return self.displayNode as! AuthorizationSequencePhoneEntryControllerNode
} }
@ -20,7 +21,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
private var validLayout: ContainerViewLayout? private var validLayout: ContainerViewLayout?
private let sharedContext: SharedAccountContext private let sharedContext: SharedAccountContext
private var account: UnauthorizedAccount private var account: UnauthorizedAccount?
private let isTestingEnvironment: Bool private let isTestingEnvironment: Bool
private let otherAccountPhoneNumbers: ((String, AccountRecordId, Bool)?, [(String, AccountRecordId, Bool)]) private let otherAccountPhoneNumbers: ((String, AccountRecordId, Bool)?, [(String, AccountRecordId, Bool)])
private let network: Network private let network: Network
@ -43,14 +44,14 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
return self.controllerNode.buttonNode return self.controllerNode.buttonNode
} }
var inProgress: Bool = false { public var inProgress: Bool = false {
didSet { didSet {
self.updateNavigationItems() self.updateNavigationItems()
self.controllerNode.inProgress = self.inProgress self.controllerNode.inProgress = self.inProgress
self.confirmationController?.inProgress = self.inProgress self.confirmationController?.inProgress = self.inProgress
} }
} }
var loginWithNumber: ((String, Bool) -> Void)? public var loginWithNumber: ((String, Bool) -> Void)?
var accountUpdated: ((UnauthorizedAccount) -> Void)? var accountUpdated: ((UnauthorizedAccount) -> Void)?
weak var confirmationController: PhoneConfirmationController? weak var confirmationController: PhoneConfirmationController?
@ -59,7 +60,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
private let hapticFeedback = HapticFeedback() private let hapticFeedback = HapticFeedback()
init(sharedContext: SharedAccountContext, account: UnauthorizedAccount, isTestingEnvironment: Bool, otherAccountPhoneNumbers: ((String, AccountRecordId, Bool)?, [(String, AccountRecordId, Bool)]), network: Network, presentationData: PresentationData, openUrl: @escaping (String) -> Void, back: @escaping () -> Void) { public init(sharedContext: SharedAccountContext, account: UnauthorizedAccount?, countriesConfiguration: CountriesConfiguration? = nil, isTestingEnvironment: Bool, otherAccountPhoneNumbers: ((String, AccountRecordId, Bool)?, [(String, AccountRecordId, Bool)]), network: Network, presentationData: PresentationData, openUrl: @escaping (String) -> Void, back: @escaping () -> Void) {
self.sharedContext = sharedContext self.sharedContext = sharedContext
self.account = account self.account = account
self.isTestingEnvironment = isTestingEnvironment self.isTestingEnvironment = isTestingEnvironment
@ -86,6 +87,10 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
if !otherAccountPhoneNumbers.1.isEmpty { if !otherAccountPhoneNumbers.1.isEmpty {
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed)) self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed))
} }
if let countriesConfiguration {
AuthorizationSequenceCountrySelectionController.setupCountryCodes(countries: countriesConfiguration.countries, codesByPrefix: countriesConfiguration.countriesByPrefix)
}
} }
required init(coder aDecoder: NSCoder) { required init(coder aDecoder: NSCoder) {
@ -113,7 +118,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
} }
} }
func updateData(countryCode: Int32, countryName: String?, number: String) { public func updateData(countryCode: Int32, countryName: String?, number: String) {
self.currentData = (countryCode, countryName, number) self.currentData = (countryCode, countryName, number)
if self.isNodeLoaded { if self.isNodeLoaded {
self.controllerNode.codeAndNumber = (countryCode, countryName, number) self.controllerNode.codeAndNumber = (countryCode, countryName, number)
@ -173,15 +178,23 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
self?.nextPressed() self?.nextPressed()
} }
loadServerCountryCodes(accountManager: sharedContext.accountManager, engine: TelegramEngineUnauthorized(account: self.account), completion: { [weak self] in if let account = self.account {
if let strongSelf = self { loadServerCountryCodes(accountManager: sharedContext.accountManager, engine: TelegramEngineUnauthorized(account: account), completion: { [weak self] in
strongSelf.controllerNode.updateCountryCode() if let strongSelf = self {
} strongSelf.controllerNode.updateCountryCode()
}) }
})
} else {
self.controllerNode.updateCountryCode()
}
}
public func updateCountryCode() {
self.controllerNode.updateCountryCode()
} }
private var animatingIn = false private var animatingIn = false
override func viewWillAppear(_ animated: Bool) { override public func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
if self.shouldAnimateIn { if self.shouldAnimateIn {
@ -197,7 +210,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
} }
} }
override func viewDidAppear(_ animated: Bool) { override public func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
if !self.animatingIn { if !self.animatingIn {
@ -205,7 +218,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
} }
} }
override func viewWillDisappear(_ animated: Bool) { override public func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated) super.viewWillDisappear(animated)
if let confirmationController = self.confirmationController { if let confirmationController = self.confirmationController {
@ -213,7 +226,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
} }
} }
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition) super.containerLayoutUpdated(layout, transition: transition)
let hadLayout = self.validLayout != nil let hadLayout = self.validLayout != nil
@ -287,4 +300,8 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
self.controllerNode.animateError() self.controllerNode.animateError()
} }
} }
public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
} }

View File

@ -18,6 +18,8 @@ import ManagedAnimationNode
private final class PhoneAndCountryNode: ASDisplayNode { private final class PhoneAndCountryNode: ASDisplayNode {
let strings: PresentationStrings let strings: PresentationStrings
let theme: PresentationTheme
let countryButton: ASButtonNode let countryButton: ASButtonNode
let phoneBackground: ASImageNode let phoneBackground: ASImageNode
let phoneInputNode: PhoneInputNode let phoneInputNode: PhoneInputNode
@ -33,6 +35,7 @@ private final class PhoneAndCountryNode: ASDisplayNode {
init(strings: PresentationStrings, theme: PresentationTheme) { init(strings: PresentationStrings, theme: PresentationTheme) {
self.strings = strings self.strings = strings
self.theme = theme
let inset: CGFloat = 24.0 let inset: CGFloat = 24.0
@ -118,37 +121,10 @@ private final class PhoneAndCountryNode: ASDisplayNode {
self.countryButton.contentHorizontalAlignment = .left self.countryButton.contentHorizontalAlignment = .left
self.countryButton.addTarget(self, action: #selector(self.countryPressed), forControlEvents: .touchUpInside) self.countryButton.addTarget(self, action: #selector(self.countryPressed), forControlEvents: .touchUpInside)
let processNumberChange: (String) -> Bool = { [weak self] number in
guard let strongSelf = self else {
return false
}
if let (country, _) = AuthorizationSequenceCountrySelectionController.lookupCountryIdByNumber(number, preferredCountries: strongSelf.preferredCountryIdForCode) {
let flagString = emojiFlagForISOCountryCode(country.id)
var localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(country.id, strings: strongSelf.strings) ?? country.name
if country.id == "FT" {
localizedName = strongSelf.strings.Login_AnonymousNumbers
}
strongSelf.countryButton.setTitle("\(flagString) \(localizedName)", with: Font.regular(20.0), with: theme.list.itemAccentColor, for: [])
strongSelf.hasCountry = true
let maskFont = Font.with(size: 20.0, design: .regular, traits: [.monospacedNumbers])
if let mask = AuthorizationSequenceCountrySelectionController.lookupPatternByNumber(number, preferredCountries: strongSelf.preferredCountryIdForCode).flatMap({ NSAttributedString(string: $0, font: maskFont, textColor: theme.list.itemPlaceholderTextColor) }) {
strongSelf.phoneInputNode.numberField.textField.attributedPlaceholder = nil
strongSelf.phoneInputNode.mask = mask
} else {
strongSelf.phoneInputNode.mask = nil
strongSelf.phoneInputNode.numberField.textField.attributedPlaceholder = NSAttributedString(string: strings.Login_PhonePlaceholder, font: Font.regular(20.0), textColor: theme.list.itemPlaceholderTextColor)
}
return true
} else {
return false
}
}
self.phoneInputNode.numberTextUpdated = { [weak self] number in self.phoneInputNode.numberTextUpdated = { [weak self] number in
if let strongSelf = self { if let strongSelf = self {
let _ = processNumberChange(strongSelf.phoneInputNode.number) let _ = strongSelf.processNumberChange(number: strongSelf.phoneInputNode.number)
if strongSelf.hasCountry { if strongSelf.hasCountry {
strongSelf.hasNumberUpdated?(!strongSelf.phoneInputNode.codeAndNumber.2.isEmpty) strongSelf.hasNumberUpdated?(!strongSelf.phoneInputNode.codeAndNumber.2.isEmpty)
@ -164,7 +140,7 @@ private final class PhoneAndCountryNode: ASDisplayNode {
strongSelf.preferredCountryIdForCode[code] = name strongSelf.preferredCountryIdForCode[code] = name
} }
if processNumberChange(strongSelf.phoneInputNode.number) { if strongSelf.processNumberChange(number: strongSelf.phoneInputNode.number) {
} else if let code = Int(code), let name = name, let countryName = countryCodeAndIdToName[CountryCodeAndId(code: code, id: name)] { } else if let code = Int(code), let name = name, let countryName = countryCodeAndIdToName[CountryCodeAndId(code: code, id: name)] {
let flagString = emojiFlagForISOCountryCode(name) let flagString = emojiFlagForISOCountryCode(name)
var localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(name, strings: strongSelf.strings) ?? countryName var localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(name, strings: strongSelf.strings) ?? countryName
@ -222,6 +198,30 @@ private final class PhoneAndCountryNode: ASDisplayNode {
} }
} }
func processNumberChange(number: String) -> Bool {
if let (country, _) = AuthorizationSequenceCountrySelectionController.lookupCountryIdByNumber(number, preferredCountries: self.preferredCountryIdForCode) {
let flagString = emojiFlagForISOCountryCode(country.id)
var localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(country.id, strings: self.strings) ?? country.name
if country.id == "FT" {
localizedName = self.strings.Login_AnonymousNumbers
}
self.countryButton.setTitle("\(flagString) \(localizedName)", with: Font.regular(20.0), with: self.theme.list.itemAccentColor, for: [])
self.hasCountry = true
let maskFont = Font.with(size: 20.0, design: .regular, traits: [.monospacedNumbers])
if let mask = AuthorizationSequenceCountrySelectionController.lookupPatternByNumber(number, preferredCountries: self.preferredCountryIdForCode).flatMap({ NSAttributedString(string: $0, font: maskFont, textColor: self.theme.list.itemPlaceholderTextColor) }) {
self.phoneInputNode.numberField.textField.attributedPlaceholder = nil
self.phoneInputNode.mask = mask
} else {
self.phoneInputNode.mask = nil
self.phoneInputNode.numberField.textField.attributedPlaceholder = NSAttributedString(string: strings.Login_PhonePlaceholder, font: Font.regular(20.0), textColor: self.theme.list.itemPlaceholderTextColor)
}
return true
} else {
return false
}
}
@objc func countryPressed() { @objc func countryPressed() {
self.selectCountryCode?() self.selectCountryCode?()
} }
@ -281,7 +281,7 @@ private final class ContactSyncNode: ASDisplayNode {
final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode { final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
private let sharedContext: SharedAccountContext private let sharedContext: SharedAccountContext
private var account: UnauthorizedAccount private var account: UnauthorizedAccount?
private let strings: PresentationStrings private let strings: PresentationStrings
private let theme: PresentationTheme private let theme: PresentationTheme
private let hasOtherAccounts: Bool private let hasOtherAccounts: Bool
@ -358,7 +358,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
return self.proceedNode return self.proceedNode
} }
init(sharedContext: SharedAccountContext, account: UnauthorizedAccount, strings: PresentationStrings, theme: PresentationTheme, debugAction: @escaping () -> Void, hasOtherAccounts: Bool) { init(sharedContext: SharedAccountContext, account: UnauthorizedAccount?, strings: PresentationStrings, theme: PresentationTheme, debugAction: @escaping () -> Void, hasOtherAccounts: Bool) {
self.sharedContext = sharedContext self.sharedContext = sharedContext
self.account = account self.account = account
@ -376,14 +376,15 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
self.titleNode = ASTextNode() self.titleNode = ASTextNode()
self.titleNode.isUserInteractionEnabled = true self.titleNode.isUserInteractionEnabled = true
self.titleNode.displaysAsynchronously = false self.titleNode.displaysAsynchronously = false
self.titleNode.attributedText = NSAttributedString(string: strings.Login_PhoneTitle, font: Font.light(30.0), textColor: theme.list.itemPrimaryTextColor) self.titleNode.attributedText = NSAttributedString(string: account == nil ? strings.Login_NewNumber : strings.Login_PhoneTitle, font: Font.light(30.0), textColor: theme.list.itemPrimaryTextColor)
self.noticeNode = ASTextNode() self.noticeNode = ASTextNode()
self.noticeNode.maximumNumberOfLines = 0 self.noticeNode.maximumNumberOfLines = 0
self.noticeNode.isUserInteractionEnabled = true self.noticeNode.isUserInteractionEnabled = true
self.noticeNode.displaysAsynchronously = false self.noticeNode.displaysAsynchronously = false
self.noticeNode.lineSpacing = 0.1 self.noticeNode.lineSpacing = 0.1
self.noticeNode.attributedText = NSAttributedString(string: strings.Login_PhoneAndCountryHelp, font: Font.regular(17.0), textColor: theme.list.itemPrimaryTextColor, paragraphAlignment: .center)
self.noticeNode.attributedText = NSAttributedString(string: account == nil ? strings.ChangePhoneNumberNumber_Help : strings.Login_PhoneAndCountryHelp, font: Font.regular(17.0), textColor: theme.list.itemPrimaryTextColor, paragraphAlignment: .center)
self.contactSyncNode = ContactSyncNode(theme: theme, strings: strings) self.contactSyncNode = ContactSyncNode(theme: theme, strings: strings)
@ -425,10 +426,12 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
} }
} }
self.tokenEventsDisposable.set((account.updateLoginTokenEvents if let account = account {
|> deliverOnMainQueue).start(next: { [weak self] _ in self.tokenEventsDisposable.set((account.updateLoginTokenEvents
self?.refreshQrToken() |> deliverOnMainQueue).start(next: { [weak self] _ in
})) self?.refreshQrToken()
}))
}
self.proceedNode.pressed = { [weak self] in self.proceedNode.pressed = { [weak self] in
self?.checkPhone?() self?.checkPhone?()
@ -517,6 +520,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
func updateCountryCode() { func updateCountryCode() {
self.phoneAndCountryNode.phoneInputNode.codeAndNumber = self.codeAndNumber self.phoneAndCountryNode.phoneInputNode.codeAndNumber = self.codeAndNumber
let _ = self.phoneAndCountryNode.processNumberChange(number: self.phoneAndCountryNode.phoneInputNode.number)
} }
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
@ -536,7 +540,10 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
let animationSize = CGSize(width: 100.0, height: 100.0) let animationSize = CGSize(width: 100.0, height: 100.0)
let titleSize = self.titleNode.measure(CGSize(width: maximumWidth, height: CGFloat.greatestFiniteMagnitude)) let titleSize = self.titleNode.measure(CGSize(width: maximumWidth, height: CGFloat.greatestFiniteMagnitude))
let noticeSize = self.noticeNode.measure(CGSize(width: min(274.0, maximumWidth - 28.0), height: CGFloat.greatestFiniteMagnitude))
let noticeInset: CGFloat = self.account == nil ? 32.0 : 0.0
let noticeSize = self.noticeNode.measure(CGSize(width: min(274.0 + noticeInset, maximumWidth - 28.0), height: CGFloat.greatestFiniteMagnitude))
let proceedHeight = self.proceedNode.updateLayout(width: maximumWidth - inset * 2.0, transition: transition) let proceedHeight = self.proceedNode.updateLayout(width: maximumWidth - inset * 2.0, transition: transition)
let proceedSize = CGSize(width: maximumWidth - inset * 2.0, height: proceedHeight) let proceedSize = CGSize(width: maximumWidth - inset * 2.0, height: proceedHeight)
@ -625,8 +632,10 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
} }
private func refreshQrToken() { private func refreshQrToken() {
guard let account = self.account else {
return
}
let sharedContext = self.sharedContext let sharedContext = self.sharedContext
let account = self.account
let tokenSignal = sharedContext.activeAccountContexts let tokenSignal = sharedContext.activeAccountContexts
|> castError(ExportAuthTransferTokenError.self) |> castError(ExportAuthTransferTokenError.self)
|> take(1) |> take(1)

View File

@ -198,8 +198,13 @@ public final class AuthorizationSequenceCountrySelectionController: ViewControll
return countryCodes return countryCodes
} }
public static func setupCountryCodes(countries: [Country], codesByPrefix: [String: (Country, Country.CountryCode)]) {
countryCodes = countries
countryCodesByPrefix = codesByPrefix
}
public static func lookupCountryNameById(_ id: String, strings: PresentationStrings) -> String? { public static func lookupCountryNameById(_ id: String, strings: PresentationStrings) -> String? {
for country in self.countries() { for country in countryCodes {
if id == country.id { if id == country.id {
let locale = localeWithStrings(strings) let locale = localeWithStrings(strings)
if let countryName = locale.localizedString(forRegionCode: id) { if let countryName = locale.localizedString(forRegionCode: id) {
@ -254,7 +259,7 @@ public final class AuthorizationSequenceCountrySelectionController: ViewControll
} }
public static func lookupCountryIdByCode(_ code: Int) -> String? { public static func lookupCountryIdByCode(_ code: Int) -> String? {
for country in self.countries() { for country in countryCodes {
for countryCode in country.countryCodes { for countryCode in country.countryCodes {
if countryCode.code == "\(code)" { if countryCode.code == "\(code)" {
return country.id return country.id

View File

@ -165,6 +165,7 @@ public final class PhoneInputNode: ASDisplayNode, UITextFieldDelegate {
} }
} }
private var didSetupPlaceholder = false
private func updatePlaceholder() { private func updatePlaceholder() {
if let mask = self.mask { if let mask = self.mask {
let mutableMask = NSMutableAttributedString(attributedString: mask) let mutableMask = NSMutableAttributedString(attributedString: mask)
@ -178,7 +179,10 @@ public final class PhoneInputNode: ASDisplayNode, UITextFieldDelegate {
} else { } else {
self.placeholderNode.attributedText = NSAttributedString(string: "") self.placeholderNode.attributedText = NSAttributedString(string: "")
} }
let _ = self.placeholderNode.updateLayout(CGSize(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude)) if !self.frame.size.width.isZero {
self.didSetupPlaceholder = true
let _ = self.placeholderNode.updateLayout(CGSize(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude))
}
} }
private let fontSize: CGFloat private let fontSize: CGFloat
@ -352,4 +356,12 @@ public final class PhoneInputNode: ASDisplayNode, UITextFieldDelegate {
self.updatePlaceholder() self.updatePlaceholder()
} }
public override func layout() {
super.layout()
if !self.didSetupPlaceholder, self.frame.width > 0.0 {
self.updatePlaceholder()
}
}
} }

View File

@ -322,7 +322,7 @@ func changePhoneNumberCodeController(context: AccountContext, phoneNumber: Strin
} |> afterDisposed { } |> afterDisposed {
actionsDisposable.dispose() actionsDisposable.dispose()
} }
let controller = ChangePhoneNumberCodeControllerImpl(context: context, state: signal, applyCodeImpl: { code in let controller = ChangePhoneNumberCodeControllerImpl(context: context, state: signal, applyCodeImpl: { code in
updateState { state in updateState { state in
return state.withUpdatedCodeText("\(code)") return state.withUpdatedCodeText("\(code)")

View File

@ -13,185 +13,324 @@ import CountrySelectionUI
import PhoneNumberFormat import PhoneNumberFormat
import CoreTelephony import CoreTelephony
import MessageUI import MessageUI
import AuthorizationUI
public final class ChangePhoneNumberController: ViewController, MFMailComposeViewControllerDelegate { public func ChangePhoneNumberController(context: AccountContext) -> ViewController {
private var controllerNode: ChangePhoneNumberControllerNode { var dismissImpl: (() -> Void)?
return self.displayNode as! ChangePhoneNumberControllerNode let presentationData = context.sharedContext.currentPresentationData.with { $0 }
}
private let context: AccountContext let requestDisposable = MetaDisposable()
let changePhoneDisposable = MetaDisposable()
private var currentData: (Int32, String?, String)? let controller = AuthorizationSequencePhoneEntryController(sharedContext: context.sharedContext, account: nil, countriesConfiguration: context.currentCountriesConfiguration.with { $0 }, isTestingEnvironment: false, otherAccountPhoneNumbers: (nil, []), network: context.account.network, presentationData: presentationData, openUrl: { _ in }, back: {
private let requestDisposable = MetaDisposable() dismissImpl?()
})
var inProgress: Bool = false { controller.loginWithNumber = { [weak controller] phoneNumber, _ in
didSet { controller?.inProgress = true
if self.inProgress {
let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: self.presentationData.theme.rootController.navigationBar.accentTextColor))
self.navigationItem.rightBarButtonItem = item
} else {
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed))
}
self.controllerNode.inProgress = self.inProgress
}
}
var loginWithNumber: ((String) -> Void)?
private let hapticFeedback = HapticFeedback()
private var presentationData: PresentationData
public init(context: AccountContext) {
self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData)) requestDisposable.set((context.engine.accountData.requestChangeAccountPhoneNumberVerification(phoneNumber: phoneNumber)
|> deliverOnMainQueue).start(next: { [weak controller] next in
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait) controller?.inProgress = false
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
self.title = self.presentationData.strings.ChangePhoneNumberNumber_Title
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed))
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.requestDisposable.dispose()
}
func updateData(countryCode: Int32, countryName: String, number: String) {
if self.currentData == nil || self.currentData! != (countryCode, countryName, number) {
self.currentData = (countryCode, countryName, number)
if self.isNodeLoaded {
self.controllerNode.codeAndNumber = (countryCode, countryName, number)
}
}
}
override public func loadDisplayNode() {
self.displayNode = ChangePhoneNumberControllerNode(presentationData: self.presentationData)
self.displayNodeDidLoad()
self.controllerNode.selectCountryCode = { [weak self] in
if let strongSelf = self {
let controller = AuthorizationSequenceCountrySelectionController(strings: strongSelf.presentationData.strings, theme: strongSelf.presentationData.theme)
controller.completeWithCountryCode = { code, name in
if let strongSelf = self {
strongSelf.updateData(countryCode: Int32(code), countryName: name, number: strongSelf.controllerNode.codeAndNumber.2)
strongSelf.controllerNode.activateInput()
}
}
strongSelf.controllerNode.view.endEditing(true)
strongSelf.push(controller)
}
}
loadServerCountryCodes(accountManager: self.context.sharedContext.accountManager, engine: self.context.engine, completion: { [weak self] in
if let strongSelf = self {
strongSelf.controllerNode.updateCountryCode()
}
})
self.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate)
}
override public func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.controllerNode.activateInput()
}
override public func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.controllerNode.activateInput()
}
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition)
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: 0.0, transition: transition)
}
@objc func nextPressed() {
let (code, _, number) = self.controllerNode.codeAndNumber
var phoneNumber = number
if let code = code {
phoneNumber = "\(code)\(phoneNumber)"
}
if !number.isEmpty {
self.inProgress = true
self.requestDisposable.set((self.context.engine.accountData.requestChangeAccountPhoneNumberVerification(phoneNumber: self.controllerNode.currentNumber) |> deliverOnMainQueue).start(next: { [weak self] next in
if let strongSelf = self {
strongSelf.inProgress = false
(strongSelf.navigationController as? NavigationController)?.pushViewController(changePhoneNumberCodeController(context: strongSelf.context, phoneNumber: strongSelf.controllerNode.currentNumber, codeData: next))
}
}, error: { [weak self] error in
if let strongSelf = self {
strongSelf.inProgress = false
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let text: String
var actions: [TextAlertAction] = []
switch error {
case .limitExceeded:
text = presentationData.strings.Login_CodeFloodError
actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {}))
case .invalidPhoneNumber:
text = presentationData.strings.Login_InvalidPhoneError
actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {}))
case .phoneNumberOccupied:
text = presentationData.strings.ChangePhone_ErrorOccupied(formatPhoneNumber(context: strongSelf.context, number: phoneNumber)).string
actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {}))
case .phoneBanned:
text = presentationData.strings.Login_PhoneBannedError
actions.append(TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_OK, action: {}))
actions.append(TextAlertAction(type: .genericAction, title: presentationData.strings.Login_PhoneNumberHelp, action: { [weak self] in
guard let strongSelf = self else {
return
}
let formattedNumber = formatPhoneNumber(context: strongSelf.context, number: number)
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
let systemVersion = UIDevice.current.systemVersion
let locale = Locale.current.identifier
let carrier = CTCarrier()
let mnc = carrier.mobileNetworkCode ?? "none"
strongSelf.presentEmailComposeController(address: "login@stel.com", subject: presentationData.strings.Login_PhoneBannedEmailSubject(formattedNumber).string, body: presentationData.strings.Login_PhoneBannedEmailBody(formattedNumber, appVersion, systemVersion, locale, mnc).string)
}))
case .generic:
text = presentationData.strings.Login_UnknownError
actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {}))
}
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: text, actions: actions), in: .window(.root))
}
}))
} else {
self.hapticFeedback.error()
self.controllerNode.animateError()
}
}
private func presentEmailComposeController(address: String, subject: String, body: String) {
if MFMailComposeViewController.canSendMail() {
let composeController = MFMailComposeViewController()
composeController.setToRecipients([address])
composeController.setSubject(subject)
composeController.setMessageBody(body, isHTML: false)
composeController.mailComposeDelegate = self
self.view.window?.rootViewController?.present(composeController, animated: true, completion: nil) var dismissImpl: (() -> Void)?
} else { let codeController = AuthorizationSequenceCodeEntryController(presentationData: presentationData, back: {
self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Login_EmailNotConfiguredError, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) dismissImpl?()
} })
codeController.loginWithCode = { [weak codeController] code in
codeController?.inProgress = true
changePhoneDisposable.set((context.engine.accountData.requestChangeAccountPhoneNumber(phoneNumber: phoneNumber, phoneCodeHash: next.hash, phoneCode: code)
|> deliverOnMainQueue).start(error: { [weak codeController] error in
if case .invalidCode = error {
codeController?.animateError(text: presentationData.strings.Login_WrongCodeError)
} else {
var resetCode = false
let text: String
switch error {
case .generic:
text = presentationData.strings.Login_UnknownError
case .invalidCode:
resetCode = true
text = presentationData.strings.Login_InvalidCodeError
case .codeExpired:
resetCode = true
text = presentationData.strings.Login_CodeExpiredError
case .limitExceeded:
resetCode = true
text = presentationData.strings.Login_CodeFloodError
}
if resetCode {
codeController?.resetCode()
}
codeController?.present(textAlertController(context: context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
}
}, completed: { [weak codeController] in
codeController?.present(OverlayStatusController(theme: presentationData.theme, type: .success), in: .window(.root))
let _ = dismissServerProvidedSuggestion(account: context.account, suggestion: .validatePhoneNumber).start()
if let navigationController = codeController?.navigationController as? NavigationController {
var viewControllers = navigationController.viewControllers
viewControllers.removeAll(where: { c in
if c is AuthorizationSequencePhoneEntryController {
return true
} else if c is AuthorizationSequenceCodeEntryController {
return true
} else {
return false
}
})
navigationController.setViewControllers(viewControllers, animated: true)
}
}))
}
codeController.openFragment = { url in
context.sharedContext.applicationBindings.openUrl(url)
}
codeController.updateData(number: formatPhoneNumber(context: context, number: phoneNumber), email: nil, codeType: next.type, nextType: nil, timeout: next.timeout, termsOfService: nil)
dismissImpl = { [weak codeController] in
codeController?.dismiss()
}
controller?.push(codeController)
}, error: { [weak controller] error in
controller?.inProgress = false
let text: String
var actions: [TextAlertAction] = []
switch error {
case .limitExceeded:
text = presentationData.strings.Login_CodeFloodError
actions.append(TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {}))
case .invalidPhoneNumber:
text = presentationData.strings.Login_InvalidPhoneError
actions.append(TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {}))
case .phoneNumberOccupied:
text = presentationData.strings.ChangePhone_ErrorOccupied(formatPhoneNumber(context: context, number: phoneNumber)).string
actions.append(TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {}))
case .phoneBanned:
text = presentationData.strings.Login_PhoneBannedError
actions.append(TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {}))
actions.append(TextAlertAction(type: .genericAction, title: presentationData.strings.Login_PhoneNumberHelp, action: { [weak controller] in
let formattedNumber = formatPhoneNumber(context: context, number: phoneNumber)
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
let systemVersion = UIDevice.current.systemVersion
let locale = Locale.current.identifier
let carrier = CTCarrier()
let mnc = carrier.mobileNetworkCode ?? "none"
if MFMailComposeViewController.canSendMail() {
let composeController = MFMailComposeViewController()
composeController.setToRecipients(["login@stel.com"])
composeController.setSubject(presentationData.strings.Login_PhoneBannedEmailSubject(formattedNumber).string)
composeController.setMessageBody(presentationData.strings.Login_PhoneBannedEmailBody(formattedNumber, appVersion, systemVersion, locale, mnc).string, isHTML: false)
composeController.mailComposeDelegate = controller
controller?.view.window?.rootViewController?.present(composeController, animated: true, completion: nil)
} else {
controller?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: presentationData.strings.Login_EmailNotConfiguredError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
}
}))
case .generic:
text = presentationData.strings.Login_UnknownError
actions.append(TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {}))
}
controller?.present(textAlertController(context: context, title: nil, text: text, actions: actions), in: .window(.root))
}))
} }
public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { dismissImpl = { [weak controller] in
controller.dismiss(animated: true, completion: nil) controller?.dismiss()
} }
Queue.mainQueue().justDispatch {
controller.updateData(countryCode: AuthorizationSequenceController.defaultCountryCode(), countryName: nil, number: "")
controller.updateCountryCode()
}
return controller
} }
//public final class ChangePhoneNumberController: ViewController, MFMailComposeViewControllerDelegate {
// private var controllerNode: ChangePhoneNumberControllerNode {
// return self.displayNode as! ChangePhoneNumberControllerNode
// }
//
// private let context: AccountContext
//
// private var currentData: (Int32, String?, String)?
// private let requestDisposable = MetaDisposable()
//
// var inProgress: Bool = false {
// didSet {
// if self.inProgress {
// let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: self.presentationData.theme.rootController.navigationBar.accentTextColor))
// self.navigationItem.rightBarButtonItem = item
// } else {
// self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed))
// }
// self.controllerNode.inProgress = self.inProgress
// }
// }
// var loginWithNumber: ((String) -> Void)?
//
// private let hapticFeedback = HapticFeedback()
//
// private var presentationData: PresentationData
//
// public init(context: AccountContext) {
// self.context = context
// self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
//
// super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
//
// self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
// self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
//
// self.title = self.presentationData.strings.ChangePhoneNumberNumber_Title
// self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.nextPressed))
// self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
// }
//
// required init(coder aDecoder: NSCoder) {
// fatalError("init(coder:) has not been implemented")
// }
//
// deinit {
// self.requestDisposable.dispose()
// }
//
// func updateData(countryCode: Int32, countryName: String, number: String) {
// if self.currentData == nil || self.currentData! != (countryCode, countryName, number) {
// self.currentData = (countryCode, countryName, number)
// if self.isNodeLoaded {
// self.controllerNode.codeAndNumber = (countryCode, countryName, number)
// }
// }
// }
//
// override public func loadDisplayNode() {
// self.displayNode = ChangePhoneNumberControllerNode(presentationData: self.presentationData)
// self.displayNodeDidLoad()
// self.controllerNode.selectCountryCode = { [weak self] in
// if let strongSelf = self {
// let controller = AuthorizationSequenceCountrySelectionController(strings: strongSelf.presentationData.strings, theme: strongSelf.presentationData.theme)
// controller.completeWithCountryCode = { code, name in
// if let strongSelf = self {
// strongSelf.updateData(countryCode: Int32(code), countryName: name, number: strongSelf.controllerNode.codeAndNumber.2)
// strongSelf.controllerNode.activateInput()
// }
// }
// strongSelf.controllerNode.view.endEditing(true)
// strongSelf.push(controller)
// }
// }
//
// loadServerCountryCodes(accountManager: self.context.sharedContext.accountManager, engine: self.context.engine, completion: { [weak self] in
// if let strongSelf = self {
// strongSelf.controllerNode.updateCountryCode()
// }
// })
//
// self.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate)
// }
//
// override public func viewWillAppear(_ animated: Bool) {
// super.viewWillAppear(animated)
//
// self.controllerNode.activateInput()
// }
//
// override public func viewDidAppear(_ animated: Bool) {
// super.viewDidAppear(animated)
//
// self.controllerNode.activateInput()
// }
//
// override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
// super.containerLayoutUpdated(layout, transition: transition)
//
// self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: 0.0, transition: transition)
// }
//
// @objc func nextPressed() {
// let (code, _, number) = self.controllerNode.codeAndNumber
// var phoneNumber = number
// if let code = code {
// phoneNumber = "\(code)\(phoneNumber)"
// }
// if !number.isEmpty {
// self.inProgress = true
// self.requestDisposable.set((self.context.engine.accountData.requestChangeAccountPhoneNumberVerification(phoneNumber: self.controllerNode.currentNumber) |> deliverOnMainQueue).start(next: { [weak self] next in
// if let strongSelf = self {
// strongSelf.inProgress = false
// (strongSelf.navigationController as? NavigationController)?.pushViewController(changePhoneNumberCodeController(context: strongSelf.context, phoneNumber: strongSelf.controllerNode.currentNumber, codeData: next))
// }
// }, error: { [weak self] error in
// if let strongSelf = self {
// strongSelf.inProgress = false
//
// let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
//
// let text: String
// var actions: [TextAlertAction] = []
// switch error {
// case .limitExceeded:
// text = presentationData.strings.Login_CodeFloodError
// actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {}))
// case .invalidPhoneNumber:
// text = presentationData.strings.Login_InvalidPhoneError
// actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {}))
// case .phoneNumberOccupied:
// text = presentationData.strings.ChangePhone_ErrorOccupied(formatPhoneNumber(context: strongSelf.context, number: phoneNumber)).string
// actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {}))
// case .phoneBanned:
// text = presentationData.strings.Login_PhoneBannedError
// actions.append(TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_OK, action: {}))
// actions.append(TextAlertAction(type: .genericAction, title: presentationData.strings.Login_PhoneNumberHelp, action: { [weak self] in
// guard let strongSelf = self else {
// return
// }
// let formattedNumber = formatPhoneNumber(context: strongSelf.context, number: number)
// let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
// let systemVersion = UIDevice.current.systemVersion
// let locale = Locale.current.identifier
// let carrier = CTCarrier()
// let mnc = carrier.mobileNetworkCode ?? "none"
//
// strongSelf.presentEmailComposeController(address: "login@stel.com", subject: presentationData.strings.Login_PhoneBannedEmailSubject(formattedNumber).string, body: presentationData.strings.Login_PhoneBannedEmailBody(formattedNumber, appVersion, systemVersion, locale, mnc).string)
// }))
// case .generic:
// text = presentationData.strings.Login_UnknownError
// actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {}))
// }
//
// strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: text, actions: actions), in: .window(.root))
// }
// }))
// } else {
// self.hapticFeedback.error()
// self.controllerNode.animateError()
// }
// }
//
// private func presentEmailComposeController(address: String, subject: String, body: String) {
// if MFMailComposeViewController.canSendMail() {
// let composeController = MFMailComposeViewController()
// composeController.setToRecipients([address])
// composeController.setSubject(subject)
// composeController.setMessageBody(body, isHTML: false)
// composeController.mailComposeDelegate = self
//
// self.view.window?.rootViewController?.present(composeController, animated: true, completion: nil)
// } else {
// self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Login_EmailNotConfiguredError, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
// }
// }
//
// public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
// controller.dismiss(animated: true, completion: nil)
// }
//}

View File

@ -1,153 +0,0 @@
import Foundation
import UIKit
import Display
import AsyncDisplayKit
import TelegramCore
import TelegramPresentationData
import TextFormat
import AccountContext
import AlertUI
import PresentationDataUtils
import AppBundle
import Markdown
import PhoneNumberFormat
private final class ChangePhoneNumberIntroControllerNode: ASDisplayNode {
var presentationData: PresentationData
let iconNode: ASImageNode
let labelNode: ASTextNode
let buttonNode: HighlightableButtonNode
var dismiss: (() -> Void)?
var action: (() -> Void)?
init(presentationData: PresentationData) {
self.presentationData = presentationData
self.iconNode = ASImageNode()
self.labelNode = ASTextNode()
self.buttonNode = HighlightableButtonNode()
super.init()
self.setViewBlock({
return UITracingLayerView()
})
self.iconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Settings/ChangePhoneIntroIcon"), color: presentationData.theme.list.freeMonoIconColor)
let textColor = self.presentationData.theme.list.freeTextColor
self.labelNode.attributedText = parseMarkdownIntoAttributedString(self.presentationData.strings.PhoneNumberHelp_Help, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: Font.regular(14.0), textColor: textColor), bold: MarkdownAttributeSet(font: Font.semibold(14.0), textColor: textColor), link: MarkdownAttributeSet(font: Font.regular(14.0), textColor: textColor), linkAttribute: { _ in return nil }), textAlignment: .center)
self.buttonNode.setTitle(self.presentationData.strings.PhoneNumberHelp_ChangeNumber, with: Font.regular(19.0), with: self.presentationData.theme.list.itemAccentColor, for: .normal)
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
self.addSubnode(self.iconNode)
self.addSubnode(self.labelNode)
self.addSubnode(self.buttonNode)
self.backgroundColor = self.presentationData.theme.list.blocksBackgroundColor
}
func animateIn() {
self.layer.animatePosition(from: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), to: self.layer.position, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
}
func animateOut() {
self.layer.animatePosition(from: self.layer.position, to: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, completion: { [weak self] _ in
if let strongSelf = self {
strongSelf.dismiss?()
}
})
}
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
var insets = layout.insets(options: [.statusBar])
insets.top += navigationBarHeight
let availableHeight = layout.size.height - insets.top - insets.bottom
let largeScreen = availableHeight >= 420.0
let contentHeight: CGFloat = largeScreen ? 420.0 : 400.0
let iconSize = self.iconNode.measure(CGSize(width: 400.0, height: 400.0))
let labelSize = self.labelNode.updateLayout(CGSize(width: 295.0, height: CGFloat.greatestFiniteMagnitude))
let buttonSize = self.buttonNode.measure(CGSize(width: 295.0, height: CGFloat.greatestFiniteMagnitude))
transition.updateFrame(node: self.iconNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - iconSize.width) / 2.0), y: insets.top + floor((availableHeight - contentHeight) / 2.0) + floor(iconSize.height * (largeScreen ? CGFloat(0.2) : CGFloat(0.5)))), size: iconSize))
transition.updateFrame(node: self.labelNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - labelSize.width) / 2.0), y: insets.top + floor((availableHeight - contentHeight) / 2.0) + floor((contentHeight - labelSize.height) / 2.0) + floor((contentHeight - iconSize.height - buttonSize.height) * 0.11)), size: labelSize))
transition.updateFrame(node: self.buttonNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - buttonSize.width) / 2.0), y: insets.top + floor((availableHeight - contentHeight) / 2.0) + contentHeight - buttonSize.height), size: buttonSize))
}
@objc func buttonPressed() {
self.action?()
}
}
public final class ChangePhoneNumberIntroController: ViewController {
private let context: AccountContext
private var didPlayPresentationAnimation = false
private var presentationData: PresentationData
public init(context: AccountContext, phoneNumber: String) {
self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
let formattedPhone = formatPhoneNumber(context: context, number: phoneNumber)
self.title = formattedPhone
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
//self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(self.cancelPressed))
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public override func loadDisplayNode() {
self.displayNode = ChangePhoneNumberIntroControllerNode(presentationData: self.presentationData)
(self.displayNode as! ChangePhoneNumberIntroControllerNode).dismiss = { [weak self] in
self?.presentingViewController?.dismiss(animated: false, completion: nil)
}
(self.displayNode as! ChangePhoneNumberIntroControllerNode).action = { [weak self] in
self?.proceed()
}
self.displayNodeDidLoad()
self.navigationBar?.updateBackgroundAlpha(0.0, transition: .immediate)
}
public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
/*if !self.didPlayPresentationAnimation {
self.didPlayPresentationAnimation = true
(self.displayNode as! ChangePhoneNumberIntroControllerNode).animateIn()
}*/
}
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition)
(self.displayNode as! ChangePhoneNumberIntroControllerNode).containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
}
@objc func cancelPressed() {
(self.displayNode as! ChangePhoneNumberIntroControllerNode).animateOut()
}
func proceed() {
self.present(textAlertController(context: self.context, title: nil, text: self.presentationData.strings.PhoneNumberHelp_Alert, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: self.presentationData.strings.TwoFactorSetup_Email_Action, action: { [weak self] in
if let strongSelf = self {
(strongSelf.navigationController as? NavigationController)?.replaceTopController(ChangePhoneNumberController(context: strongSelf.context), animated: true)
}
})]), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}
}

View File

@ -1203,7 +1203,7 @@ public func privacyAndSecurityController(context: AccountContext, initialSetting
var dismissCodeControllerImpl: (() -> Void)? var dismissCodeControllerImpl: (() -> Void)?
var presentControllerImpl: ((ViewController) -> Void)? var presentControllerImpl: ((ViewController) -> Void)?
let codeController = AuthorizationSequenceCodeEntryController(presentationData: presentationData, openUrl: { _ in }, back: { let codeController = AuthorizationSequenceCodeEntryController(presentationData: presentationData, back: {
dismissCodeControllerImpl?() dismissCodeControllerImpl?()
}) })

View File

@ -28,6 +28,7 @@ import Markdown
import WebUI import WebUI
import BotPaymentsUI import BotPaymentsUI
import PremiumUI import PremiumUI
import AuthorizationUI
private func defaultNavigationForPeerId(_ peerId: PeerId?, navigation: ChatControllerInteractionNavigateToPeer) -> ChatControllerInteractionNavigateToPeer { private func defaultNavigationForPeerId(_ peerId: PeerId?, navigation: ChatControllerInteractionNavigateToPeer) -> ChatControllerInteractionNavigateToPeer {
if case .default = navigation { if case .default = navigation {
@ -223,7 +224,9 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
dismissInput() dismissInput()
present(ProxyServerActionSheetController(context: context, server: server), nil) present(ProxyServerActionSheetController(context: context, server: server), nil)
case let .confirmationCode(code): case let .confirmationCode(code):
if let topController = navigationController?.topViewController as? ChangePhoneNumberCodeController { if let topController = navigationController?.topViewController as? AuthorizationSequenceCodeEntryController {
topController.applyConfirmationCode(code)
} else if let topController = navigationController?.topViewController as? ChangePhoneNumberCodeController {
topController.applyCode(code) topController.applyCode(code)
} else { } else {
var found = false var found = false