mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit 'd58bd7415d508d06f32d7658675b2426fa924472' into features/reply-list
This commit is contained in:
commit
f33ebbbad5
@ -1 +1 @@
|
|||||||
Subproject commit b8755bd2884d6bf651827c30e00bd0ea318e41a2
|
Subproject commit 501b4afb27745c4813a88ffa28acd901408014e4
|
@ -1 +1 @@
|
|||||||
Subproject commit d6f9a87d70781e92b95b9344c7d21d921ccc3ae2
|
Subproject commit 748e7e2b1ee5e8976ba873394cbd5e32b61818c7
|
@ -1 +1 @@
|
|||||||
Subproject commit 44e8c29afe3baa7f5fc434f4a7e83f7ac786644e
|
Subproject commit 6408d85da799ec2af053c4e2883dce3ce6d30f08
|
@ -1 +1 @@
|
|||||||
Subproject commit e890fb6c88846454c4f69abd8d265a302c0e80e4
|
Subproject commit ee185c4c20ea4384bc3cbf8ccd8705c904154abb
|
@ -769,7 +769,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
messageTags = .photo
|
messageTags = .photo
|
||||||
} else if query.hasPrefix("%video ") {
|
} else if query.hasPrefix("%video ") {
|
||||||
messageTags = .video
|
messageTags = .video
|
||||||
} else if query.hasPrefix("%file ") {
|
} else if query.hasPrefix("%file ") {
|
||||||
messageTags = .file
|
messageTags = .file
|
||||||
} else if query.hasPrefix("%music ") {
|
} else if query.hasPrefix("%music ") {
|
||||||
messageTags = .music
|
messageTags = .music
|
||||||
|
@ -25,6 +25,7 @@ private func loadCountryCodes() -> [Country] {
|
|||||||
let endOfLine = "\n"
|
let endOfLine = "\n"
|
||||||
|
|
||||||
var result: [Country] = []
|
var result: [Country] = []
|
||||||
|
var countriesByPrefix: [String: (Country, Country.CountryCode)] = [:]
|
||||||
|
|
||||||
var currentLocation = data.startIndex
|
var currentLocation = data.startIndex
|
||||||
|
|
||||||
@ -46,8 +47,11 @@ private func loadCountryCodes() -> [Country] {
|
|||||||
let maybeNameRange = data.range(of: endOfLine, options: [], range: idRange.upperBound ..< data.endIndex)
|
let maybeNameRange = data.range(of: endOfLine, options: [], range: idRange.upperBound ..< data.endIndex)
|
||||||
|
|
||||||
let countryName = locale.localizedString(forIdentifier: countryId) ?? ""
|
let countryName = locale.localizedString(forIdentifier: countryId) ?? ""
|
||||||
if let countryCodeInt = Int(countryCode) {
|
if let _ = Int(countryCode) {
|
||||||
result.append(Country(code: countryId, name: countryName, localizedName: nil, countryCodes: [Country.CountryCode(code: countryCode, prefixes: [], patterns: [])], hidden: false))
|
let code = Country.CountryCode(code: countryCode, prefixes: [], patterns: [])
|
||||||
|
let country = Country(id: countryId, name: countryName, localizedName: nil, countryCodes: [code], hidden: false)
|
||||||
|
result.append(country)
|
||||||
|
countriesByPrefix["\(code.code)"] = (country, code)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let maybeNameRange = maybeNameRange {
|
if let maybeNameRange = maybeNameRange {
|
||||||
@ -57,15 +61,35 @@ private func loadCountryCodes() -> [Country] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
countryCodesByPrefix = countriesByPrefix
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private var countryCodes: [Country] = loadCountryCodes()
|
private var countryCodes: [Country] = loadCountryCodes()
|
||||||
|
private var countryCodesByPrefix: [String: (Country, Country.CountryCode)] = [:]
|
||||||
|
|
||||||
public func loadServerCountryCodes(accountManager: AccountManager, network: Network) {
|
public func loadServerCountryCodes(accountManager: AccountManager, network: Network, completion: @escaping () -> Void) {
|
||||||
let _ = (getCountriesList(accountManager: accountManager, network: network, langCode: nil)
|
let _ = (getCountriesList(accountManager: accountManager, network: network, langCode: nil)
|
||||||
|> deliverOnMainQueue).start(next: { countries in
|
|> deliverOnMainQueue).start(next: { countries in
|
||||||
countryCodes = countries
|
countryCodes = countries
|
||||||
|
|
||||||
|
var countriesByPrefix: [String: (Country, Country.CountryCode)] = [:]
|
||||||
|
for country in countries {
|
||||||
|
for code in country.countryCodes {
|
||||||
|
if !code.prefixes.isEmpty {
|
||||||
|
for prefix in code.prefixes {
|
||||||
|
countriesByPrefix["\(code.code)\(prefix)"] = (country, code)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
countriesByPrefix[code.code] = (country, code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
countryCodesByPrefix = countriesByPrefix
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
completion()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,10 +152,26 @@ private final class AuthorizationSequenceCountrySelectionNavigationContentNode:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func removePlus(_ text: String?) -> String {
|
||||||
|
var result = ""
|
||||||
|
if let text = text {
|
||||||
|
for c in text {
|
||||||
|
if c != "+" {
|
||||||
|
result += String(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
public final class AuthorizationSequenceCountrySelectionController: ViewController {
|
public final class AuthorizationSequenceCountrySelectionController: ViewController {
|
||||||
|
static func countries() -> [Country] {
|
||||||
|
return countryCodes
|
||||||
|
}
|
||||||
|
|
||||||
public static func lookupCountryNameById(_ id: String, strings: PresentationStrings) -> String? {
|
public static func lookupCountryNameById(_ id: String, strings: PresentationStrings) -> String? {
|
||||||
for country in countryCodes {
|
for country in self.countries() {
|
||||||
if id == country.code {
|
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) {
|
||||||
return countryName
|
return countryName
|
||||||
@ -142,25 +182,74 @@ public final class AuthorizationSequenceCountrySelectionController: ViewControll
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func lookupCountryById(_ id: String) -> Country? {
|
||||||
|
return countryCodes.first { $0.id == id }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func lookupCountryIdByNumber(_ number: String, preferredCountries: [String: String]) -> (Country, Country.CountryCode)? {
|
||||||
|
let number = removePlus(number)
|
||||||
|
var results: [(Country, Country.CountryCode)]? = nil
|
||||||
|
if number.count == 1, let preferredCountryId = preferredCountries[number], let country = lookupCountryById(preferredCountryId), let code = country.countryCodes.first {
|
||||||
|
return (country, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..<number.count {
|
||||||
|
let prefix = String(number.prefix(number.count - i))
|
||||||
|
if let country = countryCodesByPrefix[prefix] {
|
||||||
|
if var currentResults = results {
|
||||||
|
if let result = currentResults.first, result.1.code.count > country.1.code.count {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
currentResults.append(country)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
results = [country]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let results = results {
|
||||||
|
if !preferredCountries.isEmpty, let (_, code) = results.first {
|
||||||
|
if let preferredCountry = preferredCountries[code.code] {
|
||||||
|
for (country, code) in results {
|
||||||
|
if country.id == preferredCountry {
|
||||||
|
return (country, code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results.first
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static func lookupCountryIdByCode(_ code: Int) -> String? {
|
public static func lookupCountryIdByCode(_ code: Int) -> String? {
|
||||||
for country in countryCodes {
|
for country in self.countries() {
|
||||||
for countryCode in country.countryCodes {
|
for countryCode in country.countryCodes {
|
||||||
if countryCode.code == "\(code)" {
|
if countryCode.code == "\(code)" {
|
||||||
return country.code
|
return country.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func lookupPatternByCode(_ code: Int) -> String? {
|
public static func lookupPatternByNumber(_ number: String, preferredCountries: [String: String]) -> String? {
|
||||||
for country in countryCodes {
|
if let (_, code) = lookupCountryIdByNumber(number, preferredCountries: preferredCountries), !code.patterns.isEmpty {
|
||||||
for countryCode in country.countryCodes {
|
var prefixes: [String: String] = [:]
|
||||||
if countryCode.code == "\(code)" {
|
for pattern in code.patterns {
|
||||||
return countryCode.patterns.first
|
let cleanPattern = pattern.replacingOccurrences(of: " ", with: "").replacingOccurrences(of: "X", with: "")
|
||||||
|
let cleanPrefix = "\(code.code)\(cleanPattern)"
|
||||||
|
prefixes[cleanPrefix] = pattern
|
||||||
|
}
|
||||||
|
for i in 0..<number.count {
|
||||||
|
let prefix = String(number.prefix(number.count - i))
|
||||||
|
if let pattern = prefixes[prefix] {
|
||||||
|
return pattern
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return code.patterns.first
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -57,12 +57,15 @@ private func loadCountryCodes() -> [(String, Int)] {
|
|||||||
|
|
||||||
private let countryCodes: [(String, Int)] = loadCountryCodes()
|
private let countryCodes: [(String, Int)] = loadCountryCodes()
|
||||||
|
|
||||||
func localizedContryNamesAndCodes(strings: PresentationStrings) -> [((String, String), String, Int)] {
|
func localizedCountryNamesAndCodes(strings: PresentationStrings) -> [((String, String), String, Int)] {
|
||||||
let locale = localeWithStrings(strings)
|
let locale = localeWithStrings(strings)
|
||||||
var result: [((String, String), String, Int)] = []
|
var result: [((String, String), String, Int)] = []
|
||||||
for (id, code) in countryCodes {
|
for country in AuthorizationSequenceCountrySelectionController.countries() {
|
||||||
if let englishCountryName = usEnglishLocale.localizedString(forRegionCode: id), let countryName = locale.localizedString(forRegionCode: id) {
|
if country.hidden {
|
||||||
result.append(((englishCountryName, countryName), id, code))
|
continue
|
||||||
|
}
|
||||||
|
if let englishCountryName = usEnglishLocale.localizedString(forRegionCode: country.id), let countryName = locale.localizedString(forRegionCode: country.id), let codeValue = country.countryCodes.first?.code, let code = Int(codeValue) {
|
||||||
|
result.append(((englishCountryName, countryName), country.id, code))
|
||||||
} else {
|
} else {
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
}
|
}
|
||||||
@ -103,7 +106,7 @@ final class AuthorizationSequenceCountrySelectionControllerNode: ASDisplayNode,
|
|||||||
self.searchTableView.contentInsetAdjustmentBehavior = .never
|
self.searchTableView.contentInsetAdjustmentBehavior = .never
|
||||||
}
|
}
|
||||||
|
|
||||||
let countryNamesAndCodes = localizedContryNamesAndCodes(strings: strings)
|
let countryNamesAndCodes = localizedCountryNamesAndCodes(strings: strings)
|
||||||
|
|
||||||
var sections: [(String, [((String, String), String, Int)])] = []
|
var sections: [(String, [((String, String), String, Int)])] = []
|
||||||
for (names, id, code) in countryNamesAndCodes.sorted(by: { lhs, rhs in
|
for (names, id, code) in countryNamesAndCodes.sorted(by: { lhs, rhs in
|
||||||
@ -116,8 +119,7 @@ final class AuthorizationSequenceCountrySelectionControllerNode: ASDisplayNode,
|
|||||||
sections[sections.count - 1].1.append((names, id, code))
|
sections[sections.count - 1].1.append((names, id, code))
|
||||||
}
|
}
|
||||||
self.sections = sections
|
self.sections = sections
|
||||||
var sectionTitles = sections.map { $0.0 }
|
self.sectionTitles = sections.map { $0.0 }
|
||||||
self.sectionTitles = sectionTitles
|
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
|
@ -1,6 +1,29 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import AppBundle
|
import AppBundle
|
||||||
|
|
||||||
|
public func emojiFlagForISOCountryCode(_ countryCode: String) -> String {
|
||||||
|
if countryCode.count != 2 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if countryCode == "XG" {
|
||||||
|
return "🛰️"
|
||||||
|
} else if countryCode == "XV" {
|
||||||
|
return "🌍"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ["YL"].contains(countryCode) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
let base : UInt32 = 127397
|
||||||
|
var s = ""
|
||||||
|
for v in countryCode.unicodeScalars {
|
||||||
|
s.unicodeScalars.append(UnicodeScalar(base + v.value)!)
|
||||||
|
}
|
||||||
|
return String(s)
|
||||||
|
}
|
||||||
|
|
||||||
private func loadCountriesInfo() -> [(Int, String, String)] {
|
private func loadCountriesInfo() -> [(Int, String, String)] {
|
||||||
guard let filePath = getAppBundle().path(forResource: "PhoneCountries", ofType: "txt") else {
|
guard let filePath = getAppBundle().path(forResource: "PhoneCountries", ofType: "txt") else {
|
||||||
return []
|
return []
|
||||||
|
@ -128,10 +128,14 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||||||
|
|
||||||
self.collapsed = collapsed
|
self.collapsed = collapsed
|
||||||
|
|
||||||
|
guard let (size, _, _) = self.containerLayout else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let alpha: CGFloat = collapsed ? 0.0 : 1.0
|
let alpha: CGFloat = collapsed ? 0.0 : 1.0
|
||||||
self.leftTimestampNode.alpha = alpha
|
self.leftTimestampNode.alpha = alpha
|
||||||
self.rightTimestampNode.alpha = alpha
|
self.rightTimestampNode.alpha = alpha
|
||||||
self.infoNode.alpha = alpha
|
self.infoNode.alpha = size.width < size.height && !self.collapsed ? 1.0 : 0.0
|
||||||
self.updateScrubberVisibility(animated: animated)
|
self.updateScrubberVisibility(animated: animated)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +165,7 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||||||
self.leftTimestampNode.status = mappedStatus
|
self.leftTimestampNode.status = mappedStatus
|
||||||
self.rightTimestampNode.status = mappedStatus
|
self.rightTimestampNode.status = mappedStatus
|
||||||
|
|
||||||
if let mappedStatus = mappedStatus {
|
if let mappedStatus = mappedStatus, false {
|
||||||
self.chapterDisposable.set((mappedStatus
|
self.chapterDisposable.set((mappedStatus
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||||
if let strongSelf = self, status.duration > 1.0 {
|
if let strongSelf = self, status.duration > 1.0 {
|
||||||
|
@ -141,7 +141,7 @@ public func legacyAttachmentMenu(context: AccountContext, peer: Peer, editMediaO
|
|||||||
if peer is TelegramUser {
|
if peer is TelegramUser {
|
||||||
carouselItem.hasTimer = hasSchedule
|
carouselItem.hasTimer = hasSchedule
|
||||||
}
|
}
|
||||||
carouselItem.hasSilentPosting = !isSecretChat
|
carouselItem.hasSilentPosting = true
|
||||||
}
|
}
|
||||||
carouselItem.hasSchedule = hasSchedule
|
carouselItem.hasSchedule = hasSchedule
|
||||||
carouselItem.reminder = peer.id == context.account.peerId
|
carouselItem.reminder = peer.id == context.account.peerId
|
||||||
|
@ -39,7 +39,7 @@ public func configureLegacyAssetPicker(_ controller: TGMediaAssetsController, co
|
|||||||
if peer is TelegramUser {
|
if peer is TelegramUser {
|
||||||
controller.hasTimer = hasSchedule
|
controller.hasTimer = hasSchedule
|
||||||
}
|
}
|
||||||
controller.hasSilentPosting = !isSecretChat
|
controller.hasSilentPosting = true
|
||||||
}
|
}
|
||||||
controller.hasSchedule = hasSchedule
|
controller.hasSchedule = hasSchedule
|
||||||
controller.reminder = peer.id == context.account.peerId
|
controller.reminder = peer.id == context.account.peerId
|
||||||
|
@ -78,6 +78,7 @@ private func cleanSuffix(_ text: String) -> String {
|
|||||||
|
|
||||||
extension String {
|
extension String {
|
||||||
func applyPatternOnNumbers(pattern: String, replacementCharacter: Character) -> String {
|
func applyPatternOnNumbers(pattern: String, replacementCharacter: Character) -> String {
|
||||||
|
let pattern = pattern.replacingOccurrences( of: "[0-9]", with: "X", options: .regularExpression)
|
||||||
var pureNumber = self.replacingOccurrences( of: "[^0-9]", with: "", options: .regularExpression)
|
var pureNumber = self.replacingOccurrences( of: "[^0-9]", with: "", options: .regularExpression)
|
||||||
for index in 0 ..< pattern.count {
|
for index in 0 ..< pattern.count {
|
||||||
guard index < pureNumber.count else { return pureNumber }
|
guard index < pureNumber.count else { return pureNumber }
|
||||||
@ -165,6 +166,7 @@ public final class PhoneInputNode: ASDisplayNode, UITextFieldDelegate {
|
|||||||
public var returnAction: (() -> Void)?
|
public var returnAction: (() -> Void)?
|
||||||
|
|
||||||
private let phoneFormatter = InteractivePhoneFormatter()
|
private let phoneFormatter = InteractivePhoneFormatter()
|
||||||
|
public var customFormatter: ((String) -> String?)?
|
||||||
|
|
||||||
public var mask: NSAttributedString? {
|
public var mask: NSAttributedString? {
|
||||||
didSet {
|
didSet {
|
||||||
@ -175,8 +177,12 @@ public final class PhoneInputNode: ASDisplayNode, UITextFieldDelegate {
|
|||||||
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)
|
||||||
mutableMask.replaceCharacters(in: NSRange(location: 0, length: mask.string.count), with: mask.string.replacingOccurrences(of: "X", with: "-"))
|
mutableMask.replaceCharacters(in: NSRange(location: 0, length: mask.string.count), with: mask.string.replacingOccurrences(of: "X", with: "–"))
|
||||||
mutableMask.addAttribute(.foregroundColor, value: UIColor.clear, range: NSRange(location: 0, length: min(self.numberField.textField.text?.count ?? 0, mask.string.count)))
|
if let text = self.numberField.textField.text {
|
||||||
|
mutableMask.replaceCharacters(in: NSRange(location: 0, length: min(text.count, mask.string.count)), with: text)
|
||||||
|
}
|
||||||
|
mutableMask.addAttribute(.foregroundColor, value: UIColor.clear, range: NSRange(location: 0, length: min(self.numberField.textField.text?.count ?? 0, mutableMask.string.count)))
|
||||||
|
mutableMask.addAttribute(.kern, value: 1.6, range: NSRange(location: 0, length: mask.string.count))
|
||||||
self.placeholderNode.attributedText = mutableMask
|
self.placeholderNode.attributedText = mutableMask
|
||||||
} else {
|
} else {
|
||||||
self.placeholderNode.attributedText = NSAttributedString(string: "")
|
self.placeholderNode.attributedText = NSAttributedString(string: "")
|
||||||
@ -212,7 +218,7 @@ public final class PhoneInputNode: ASDisplayNode, UITextFieldDelegate {
|
|||||||
} else {
|
} else {
|
||||||
self.numberField.textField.keyboardType = .numberPad
|
self.numberField.textField.keyboardType = .numberPad
|
||||||
}
|
}
|
||||||
self.numberField.textField.defaultTextAttributes = [NSAttributedString.Key.font: font, NSAttributedString.Key.kern: 2.0]
|
self.numberField.textField.defaultTextAttributes = [NSAttributedString.Key.font: font, NSAttributedString.Key.kern: 1.6]
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.addSubnode(self.countryCodeField)
|
self.addSubnode(self.countryCodeField)
|
||||||
@ -260,7 +266,12 @@ public final class PhoneInputNode: ASDisplayNode, UITextFieldDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateNumber(_ inputText: String, tryRestoringInputPosition: Bool = true, forceNotifyCountryCodeUpdated: Bool = false) {
|
private func updateNumber(_ inputText: String, tryRestoringInputPosition: Bool = true, forceNotifyCountryCodeUpdated: Bool = false) {
|
||||||
let (regionPrefix, text) = self.phoneFormatter.updateText(inputText)
|
var (regionPrefix, text) = self.phoneFormatter.updateText(inputText)
|
||||||
|
|
||||||
|
if let customFormatter = self.customFormatter, let customRegionPrefix = customFormatter(inputText) {
|
||||||
|
regionPrefix = "+\(customRegionPrefix)"
|
||||||
|
text = inputText
|
||||||
|
}
|
||||||
|
|
||||||
var realRegionPrefix: String
|
var realRegionPrefix: String
|
||||||
var numberText: String
|
var numberText: String
|
||||||
|
@ -87,6 +87,12 @@ final class ChangePhoneNumberController: ViewController {
|
|||||||
strongSelf.push(controller)
|
strongSelf.push(controller)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadServerCountryCodes(accountManager: self.context.sharedContext.accountManager, network: self.context.account.network, completion: { [weak self] in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.controllerNode.updateCountryCode()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
@ -91,6 +91,8 @@ final class ChangePhoneNumberControllerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var preferredCountryIdForCode: [String: String] = [:]
|
||||||
|
|
||||||
var selectCountryCode: (() -> Void)?
|
var selectCountryCode: (() -> Void)?
|
||||||
|
|
||||||
var inProgress: Bool = false {
|
var inProgress: Bool = false {
|
||||||
@ -155,9 +157,43 @@ final class ChangePhoneNumberControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
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)
|
||||||
|
let localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(country.id, strings: strongSelf.presentationData.strings) ?? country.name
|
||||||
|
strongSelf.countryButton.setTitle("\(flagString) \(localizedName)", with: Font.regular(17.0), with: strongSelf.presentationData.theme.list.itemPrimaryTextColor, for: [])
|
||||||
|
|
||||||
|
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: strongSelf.presentationData.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: strongSelf.presentationData.strings.Login_PhonePlaceholder, font: Font.regular(20.0), textColor: strongSelf.presentationData.theme.list.itemPlaceholderTextColor)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.phoneInputNode.numberTextUpdated = { [weak self] number in
|
||||||
|
if let strongSelf = self {
|
||||||
|
let _ = processNumberChange(strongSelf.phoneInputNode.number)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.phoneInputNode.countryCodeUpdated = { [weak self] code, name in
|
self.phoneInputNode.countryCodeUpdated = { [weak self] code, name in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let code = Int(code), let name = name, let countryName = countryCodeAndIdToName[CountryCodeAndId(code: code, id: name)] {
|
if let name = name {
|
||||||
|
strongSelf.preferredCountryIdForCode[code] = name
|
||||||
|
}
|
||||||
|
|
||||||
|
if processNumberChange(strongSelf.phoneInputNode.number) {
|
||||||
|
} else if let code = Int(code), let name = name, let countryName = countryCodeAndIdToName[CountryCodeAndId(code: code, id: name)] {
|
||||||
let localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(name, strings: strongSelf.presentationData.strings) ?? countryName
|
let localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(name, strings: strongSelf.presentationData.strings) ?? countryName
|
||||||
strongSelf.countryButton.setTitle(localizedName, with: Font.regular(17.0), with: strongSelf.presentationData.theme.list.itemPrimaryTextColor, for: [])
|
strongSelf.countryButton.setTitle(localizedName, with: Font.regular(17.0), with: strongSelf.presentationData.theme.list.itemPrimaryTextColor, for: [])
|
||||||
} else if let code = Int(code), let (_, countryName) = countryCodeToIdAndName[code] {
|
} else if let code = Int(code), let (_, countryName) = countryCodeToIdAndName[code] {
|
||||||
@ -168,6 +204,14 @@ final class ChangePhoneNumberControllerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.phoneInputNode.customFormatter = { number in
|
||||||
|
if let (_, code) = AuthorizationSequenceCountrySelectionController.lookupCountryIdByNumber(number, preferredCountries: [:]) {
|
||||||
|
return code.code
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var countryId: String? = nil
|
var countryId: String? = nil
|
||||||
let networkInfo = CTTelephonyNetworkInfo()
|
let networkInfo = CTTelephonyNetworkInfo()
|
||||||
if let carrier = networkInfo.subscriberCellularProvider {
|
if let carrier = networkInfo.subscriberCellularProvider {
|
||||||
@ -193,6 +237,10 @@ final class ChangePhoneNumberControllerNode: ASDisplayNode {
|
|||||||
self.phoneInputNode.number = "+\(countryCodeAndId.0)"
|
self.phoneInputNode.number = "+\(countryCodeAndId.0)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateCountryCode() {
|
||||||
|
self.phoneInputNode.codeAndNumber = self.codeAndNumber
|
||||||
|
}
|
||||||
|
|
||||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
var insets = layout.insets(options: [.statusBar, .input])
|
var insets = layout.insets(options: [.statusBar, .input])
|
||||||
insets.left = layout.safeInsets.left
|
insets.left = layout.safeInsets.left
|
||||||
@ -215,12 +263,14 @@ final class ChangePhoneNumberControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
let countryCodeFrame = CGRect(origin: CGPoint(x: 9.0, y: navigationHeight + 44.0 + 1.0), size: CGSize(width: 45.0, height: 44.0))
|
let countryCodeFrame = CGRect(origin: CGPoint(x: 9.0, y: navigationHeight + 44.0 + 1.0), size: CGSize(width: 45.0, height: 44.0))
|
||||||
let numberFrame = CGRect(origin: CGPoint(x: 70.0, y: navigationHeight + 44.0 + 1.0), size: CGSize(width: layout.size.width - 70.0 - 8.0, height: 44.0))
|
let numberFrame = CGRect(origin: CGPoint(x: 70.0, y: navigationHeight + 44.0 + 1.0), size: CGSize(width: layout.size.width - 70.0 - 8.0, height: 44.0))
|
||||||
|
let placeholderFrame = numberFrame.offsetBy(dx: -1.0, dy: 16.0)
|
||||||
|
|
||||||
let phoneInputFrame = countryCodeFrame.union(numberFrame)
|
let phoneInputFrame = countryCodeFrame.union(numberFrame)
|
||||||
|
|
||||||
transition.updateFrame(node: self.phoneInputNode, frame: phoneInputFrame)
|
transition.updateFrame(node: self.phoneInputNode, frame: phoneInputFrame)
|
||||||
transition.updateFrame(node: self.phoneInputNode.countryCodeField, frame: countryCodeFrame.offsetBy(dx: -phoneInputFrame.minX, dy: -phoneInputFrame.minY))
|
transition.updateFrame(node: self.phoneInputNode.countryCodeField, frame: countryCodeFrame.offsetBy(dx: -phoneInputFrame.minX, dy: -phoneInputFrame.minY))
|
||||||
transition.updateFrame(node: self.phoneInputNode.numberField, frame: numberFrame.offsetBy(dx: -phoneInputFrame.minX, dy: -phoneInputFrame.minY))
|
transition.updateFrame(node: self.phoneInputNode.numberField, frame: numberFrame.offsetBy(dx: -phoneInputFrame.minX, dy: -phoneInputFrame.minY))
|
||||||
|
transition.updateFrame(node: self.phoneInputNode.placeholderNode, frame: placeholderFrame.offsetBy(dx: -phoneInputFrame.minX, dy: -phoneInputFrame.minY))
|
||||||
|
|
||||||
transition.updateFrame(node: self.noticeNode, frame: CGRect(origin: CGPoint(x: 15.0 + insets.left, y: navigationHeight + inputHeight + 8.0), size: noticeSize))
|
transition.updateFrame(node: self.noticeNode, frame: CGRect(origin: CGPoint(x: 15.0 + insets.left, y: navigationHeight + inputHeight + 8.0), size: noticeSize))
|
||||||
}
|
}
|
||||||
|
@ -593,25 +593,25 @@ public final class ShareController: ViewController {
|
|||||||
}
|
}
|
||||||
self.controllerNode.shareExternal = { [weak self] in
|
self.controllerNode.shareExternal = { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if case let .messages(messages) = strongSelf.subject, let message = messages.first, let peer = message.peers[message.id.peerId] {
|
// if case let .messages(messages) = strongSelf.subject, let message = messages.first, let peer = message.peers[message.id.peerId] {
|
||||||
let renderer = MessageStoryRenderer(context: strongSelf.currentContext, messages: messages)
|
// let renderer = MessageStoryRenderer(context: strongSelf.currentContext, messages: messages)
|
||||||
|
//
|
||||||
let layout = ContainerViewLayout(size: CGSize(width: 414.0, height: 896.0), metrics: LayoutMetrics(widthClass: .compact, heightClass: .compact), deviceMetrics: .iPhoneX, intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: 0.0, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false)
|
// let layout = ContainerViewLayout(size: CGSize(width: 414.0, height: 896.0), metrics: LayoutMetrics(widthClass: .compact, heightClass: .compact), deviceMetrics: .iPhoneX, intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: 0.0, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false)
|
||||||
renderer.update(layout: layout) { image in
|
// renderer.update(layout: layout) { image in
|
||||||
if let data = image?.pngData() {
|
// if let data = image?.pngData() {
|
||||||
let pasteboardItems: [[String: Any]] = [["com.instagram.sharedSticker.backgroundImage": data,
|
// let pasteboardItems: [[String: Any]] = [["com.instagram.sharedSticker.backgroundImage": data,
|
||||||
"com.instagram.sharedSticker.contentURL": "https://t.me/\(peer.addressName ?? "")/\(message.id.id)"]]
|
// "com.instagram.sharedSticker.contentURL": "https://t.me/\(peer.addressName ?? "")/\(message.id.id)"]]
|
||||||
if #available(iOS 10.0, *) {
|
// if #available(iOS 10.0, *) {
|
||||||
UIPasteboard.general.setItems(pasteboardItems, options: [.expirationDate: Date().addingTimeInterval(5 * 60)])
|
// UIPasteboard.general.setItems(pasteboardItems, options: [.expirationDate: Date().addingTimeInterval(5 * 60)])
|
||||||
} else {
|
// } else {
|
||||||
// UIPasteboard.general.setItems(pasteboardItems)
|
//// UIPasteboard.general.setItems(pasteboardItems)
|
||||||
}
|
// }
|
||||||
strongSelf.sharedContext.applicationBindings.openUrl("instagram-stories://share")
|
// strongSelf.sharedContext.applicationBindings.openUrl("instagram-stories://share")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
return .complete()
|
// return .complete()
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
var collectableItems: [CollectableExternalShareItem] = []
|
var collectableItems: [CollectableExternalShareItem] = []
|
||||||
|
@ -300,15 +300,12 @@ private class CallControllerToastItemNode: ASDisplayNode {
|
|||||||
let initialFrame = CGRect(x: floor((self.frame.width - 44.0) / 2.0), y: 0.0, width: 44.0, height: 28.0)
|
let initialFrame = CGRect(x: floor((self.frame.width - 44.0) / 2.0), y: 0.0, width: 44.0, height: 28.0)
|
||||||
|
|
||||||
self.clipNode.frame = initialFrame
|
self.clipNode.frame = initialFrame
|
||||||
// self.effectView.frame = CGRect(origin: CGPoint(), size: initialFrame.size)
|
|
||||||
|
|
||||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||||
self.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.45, damping: 105.0, completion: { _ in
|
self.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.3, damping: 105.0, completion: { _ in
|
||||||
self.clipNode.frame = targetFrame
|
self.clipNode.frame = targetFrame
|
||||||
// self.effectView.frame = CGRect(origin: CGPoint(), size: targetFrame.size)
|
|
||||||
|
|
||||||
self.clipNode.layer.animateFrame(from: initialFrame, to: targetFrame, duration: 0.35, timingFunction: kCAMediaTimingFunctionSpring)
|
self.clipNode.layer.animateFrame(from: initialFrame, to: targetFrame, duration: 0.35, timingFunction: kCAMediaTimingFunctionSpring)
|
||||||
// self.effectView.layer.animateFrame(from: initialFrame, to: targetFrame, duration: 0.35, timingFunction: kCAMediaTimingFunctionSpring)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +166,7 @@ private var declaredEncodables: Void = {
|
|||||||
declareEncodable(TelegramMediaImage.VideoRepresentation.self, f: { TelegramMediaImage.VideoRepresentation(decoder: $0) })
|
declareEncodable(TelegramMediaImage.VideoRepresentation.self, f: { TelegramMediaImage.VideoRepresentation(decoder: $0) })
|
||||||
declareEncodable(Country.self, f: { Country(decoder: $0) })
|
declareEncodable(Country.self, f: { Country(decoder: $0) })
|
||||||
declareEncodable(Country.CountryCode.self, f: { Country.CountryCode(decoder: $0) })
|
declareEncodable(Country.CountryCode.self, f: { Country.CountryCode(decoder: $0) })
|
||||||
|
declareEncodable(CountriesList.self, f: { CountriesList(decoder: $0) })
|
||||||
|
|
||||||
return
|
return
|
||||||
}()
|
}()
|
||||||
|
@ -7,7 +7,7 @@ import SyncCore
|
|||||||
|
|
||||||
public struct Country: PostboxCoding, Equatable {
|
public struct Country: PostboxCoding, Equatable {
|
||||||
public static func == (lhs: Country, rhs: Country) -> Bool {
|
public static func == (lhs: Country, rhs: Country) -> Bool {
|
||||||
return lhs.code == rhs.code && lhs.name == rhs.name && lhs.localizedName == rhs.localizedName && lhs.countryCodes == rhs.countryCodes && lhs.hidden == rhs.hidden
|
return lhs.id == rhs.id && lhs.name == rhs.name && lhs.localizedName == rhs.localizedName && lhs.countryCodes == rhs.countryCodes && lhs.hidden == rhs.hidden
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct CountryCode: PostboxCoding, Equatable {
|
public struct CountryCode: PostboxCoding, Equatable {
|
||||||
@ -34,14 +34,14 @@ public struct Country: PostboxCoding, Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public let code: String
|
public let id: String
|
||||||
public let name: String
|
public let name: String
|
||||||
public let localizedName: String?
|
public let localizedName: String?
|
||||||
public let countryCodes: [CountryCode]
|
public let countryCodes: [CountryCode]
|
||||||
public let hidden: Bool
|
public let hidden: Bool
|
||||||
|
|
||||||
public init(code: String, name: String, localizedName: String?, countryCodes: [CountryCode], hidden: Bool) {
|
public init(id: String, name: String, localizedName: String?, countryCodes: [CountryCode], hidden: Bool) {
|
||||||
self.code = code
|
self.id = id
|
||||||
self.name = name
|
self.name = name
|
||||||
self.localizedName = localizedName
|
self.localizedName = localizedName
|
||||||
self.countryCodes = countryCodes
|
self.countryCodes = countryCodes
|
||||||
@ -49,7 +49,7 @@ public struct Country: PostboxCoding, Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public init(decoder: PostboxDecoder) {
|
public init(decoder: PostboxDecoder) {
|
||||||
self.code = decoder.decodeStringForKey("c", orElse: "")
|
self.id = decoder.decodeStringForKey("c", orElse: "")
|
||||||
self.name = decoder.decodeStringForKey("n", orElse: "")
|
self.name = decoder.decodeStringForKey("n", orElse: "")
|
||||||
self.localizedName = decoder.decodeOptionalStringForKey("ln")
|
self.localizedName = decoder.decodeOptionalStringForKey("ln")
|
||||||
self.countryCodes = decoder.decodeObjectArrayForKey("cc").map { $0 as! CountryCode }
|
self.countryCodes = decoder.decodeObjectArrayForKey("cc").map { $0 as! CountryCode }
|
||||||
@ -57,7 +57,7 @@ public struct Country: PostboxCoding, Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func encode(_ encoder: PostboxEncoder) {
|
public func encode(_ encoder: PostboxEncoder) {
|
||||||
encoder.encodeString(self.code, forKey: "c")
|
encoder.encodeString(self.id, forKey: "c")
|
||||||
encoder.encodeString(self.name, forKey: "n")
|
encoder.encodeString(self.name, forKey: "n")
|
||||||
if let localizedName = self.localizedName {
|
if let localizedName = self.localizedName {
|
||||||
encoder.encodeString(localizedName, forKey: "ln")
|
encoder.encodeString(localizedName, forKey: "ln")
|
||||||
@ -130,6 +130,7 @@ public func getCountriesList(accountManager: AccountManager, network: Network, l
|
|||||||
return fetch(nil, nil)
|
return fetch(nil, nil)
|
||||||
} else {
|
} else {
|
||||||
return accountManager.sharedData(keys: [SharedDataKeys.countriesList])
|
return accountManager.sharedData(keys: [SharedDataKeys.countriesList])
|
||||||
|
|> take(1)
|
||||||
|> map { sharedData -> ([Country], Int32) in
|
|> map { sharedData -> ([Country], Int32) in
|
||||||
if let countriesList = sharedData.entries[SharedDataKeys.countriesList] as? CountriesList {
|
if let countriesList = sharedData.entries[SharedDataKeys.countriesList] as? CountriesList {
|
||||||
return (countriesList.countries, countriesList.hash)
|
return (countriesList.countries, countriesList.hash)
|
||||||
@ -158,7 +159,7 @@ extension Country {
|
|||||||
init(apiCountry: Api.help.Country) {
|
init(apiCountry: Api.help.Country) {
|
||||||
switch apiCountry {
|
switch apiCountry {
|
||||||
case let .country(flags, iso2, defaultName, name, countryCodes):
|
case let .country(flags, iso2, defaultName, name, countryCodes):
|
||||||
self.init(code: iso2, name: defaultName, localizedName: name, countryCodes: countryCodes.map { Country.CountryCode(apiCountryCode: $0) }, hidden: (flags & 1 << 0) != 0)
|
self.init(id: iso2, name: defaultName, localizedName: name, countryCodes: countryCodes.map { Country.CountryCode(apiCountryCode: $0) }, hidden: (flags & 1 << 0) != 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -323,8 +323,8 @@ public func searchMessages(account: Account, location: SearchMessagesLocation, q
|
|||||||
|> mapToSignal { result, additionalResult -> Signal<(SearchMessagesResult, SearchMessagesState), NoError> in
|
|> mapToSignal { result, additionalResult -> Signal<(SearchMessagesResult, SearchMessagesState), NoError> in
|
||||||
return account.postbox.transaction { transaction -> (SearchMessagesResult, SearchMessagesState) in
|
return account.postbox.transaction { transaction -> (SearchMessagesResult, SearchMessagesState) in
|
||||||
var additional: SearchMessagesPeerState? = mergedState(transaction: transaction, state: state?.additional, result: additionalResult)
|
var additional: SearchMessagesPeerState? = mergedState(transaction: transaction, state: state?.additional, result: additionalResult)
|
||||||
if state?.additional == nil, case .general = location {
|
if state?.additional == nil, case let .general(tags) = location {
|
||||||
let secretMessages = transaction.searchMessages(peerId: nil, query: query, tags: nil)
|
let secretMessages = transaction.searchMessages(peerId: nil, query: query, tags: tags)
|
||||||
var readStates: [PeerId: CombinedPeerReadState] = [:]
|
var readStates: [PeerId: CombinedPeerReadState] = [:]
|
||||||
for message in secretMessages {
|
for message in secretMessages {
|
||||||
if let readState = transaction.getCombinedPeerReadState(message.id.peerId) {
|
if let readState = transaction.getCombinedPeerReadState(message.id.peerId) {
|
||||||
|
@ -57,9 +57,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
|
|||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.openUrl = openUrl
|
self.openUrl = openUrl
|
||||||
self.back = back
|
self.back = back
|
||||||
|
|
||||||
loadServerCountryCodes(accountManager: sharedContext.accountManager, network: account.network)
|
|
||||||
|
|
||||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: AuthorizationSequenceController.navigationBarTheme(presentationData.theme), strings: NavigationBarStrings(presentationStrings: presentationData.strings)))
|
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: AuthorizationSequenceController.navigationBarTheme(presentationData.theme), strings: NavigationBarStrings(presentationStrings: presentationData.strings)))
|
||||||
|
|
||||||
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||||
@ -140,6 +138,12 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
|
|||||||
self.controllerNode.checkPhone = { [weak self] in
|
self.controllerNode.checkPhone = { [weak self] in
|
||||||
self?.nextPressed()
|
self?.nextPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadServerCountryCodes(accountManager: sharedContext.accountManager, network: account.network, completion: { [weak self] in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.controllerNode.updateCountryCode()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
@ -185,7 +189,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
|
|||||||
self.loginWithNumber?(self.controllerNode.currentNumber, self.controllerNode.syncContacts)
|
self.loginWithNumber?(self.controllerNode.currentNumber, self.controllerNode.syncContacts)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hapticFeedback.error()
|
self.hapticFeedback.error()
|
||||||
self.controllerNode.animateError()
|
self.controllerNode.animateError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,24 +13,6 @@ import SwiftSignalKit
|
|||||||
import Postbox
|
import Postbox
|
||||||
import AccountContext
|
import AccountContext
|
||||||
|
|
||||||
private func emojiFlagForISOCountryCode(_ countryCode: NSString) -> String {
|
|
||||||
if countryCode.length != 2 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
let base: UInt32 = 127462 - 65
|
|
||||||
let first: UInt32 = base + UInt32(countryCode.character(at: 0))
|
|
||||||
let second: UInt32 = base + UInt32(countryCode.character(at: 1))
|
|
||||||
|
|
||||||
var data = Data()
|
|
||||||
data.count = 8
|
|
||||||
data.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt32>) -> Void in
|
|
||||||
bytes[0] = first
|
|
||||||
bytes[1] = second
|
|
||||||
}
|
|
||||||
return String(data: data, encoding: String.Encoding.utf32LittleEndian) ?? ""
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class PhoneAndCountryNode: ASDisplayNode {
|
private final class PhoneAndCountryNode: ASDisplayNode {
|
||||||
let strings: PresentationStrings
|
let strings: PresentationStrings
|
||||||
let countryButton: ASButtonNode
|
let countryButton: ASButtonNode
|
||||||
@ -40,6 +22,8 @@ private final class PhoneAndCountryNode: ASDisplayNode {
|
|||||||
var selectCountryCode: (() -> Void)?
|
var selectCountryCode: (() -> Void)?
|
||||||
var checkPhone: (() -> Void)?
|
var checkPhone: (() -> Void)?
|
||||||
|
|
||||||
|
var preferredCountryIdForCode: [String: String] = [:]
|
||||||
|
|
||||||
init(strings: PresentationStrings, theme: PresentationTheme) {
|
init(strings: PresentationStrings, theme: PresentationTheme) {
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
|
|
||||||
@ -124,33 +108,70 @@ private final class PhoneAndCountryNode: ASDisplayNode {
|
|||||||
self.countryButton.contentEdgeInsets = UIEdgeInsets(top: 0.0, left: 15.0, bottom: 10.0, right: 0.0)
|
self.countryButton.contentEdgeInsets = UIEdgeInsets(top: 0.0, left: 15.0, bottom: 10.0, right: 0.0)
|
||||||
self.countryButton.contentHorizontalAlignment = .left
|
self.countryButton.contentHorizontalAlignment = .left
|
||||||
|
|
||||||
// self.phoneInputNode.numberField.textField.attributedPlaceholder = NSAttributedString(string: strings.Login_PhonePlaceholder, font: Font.regular(20.0), textColor: theme.list.itemPlaceholderTextColor)
|
|
||||||
|
|
||||||
self.countryButton.addTarget(self, action: #selector(self.countryPressed), forControlEvents: .touchUpInside)
|
self.countryButton.addTarget(self, action: #selector(self.countryPressed), forControlEvents: .touchUpInside)
|
||||||
|
|
||||||
self.phoneInputNode.countryCodeUpdated = { [weak self] code, name in
|
let processNumberChange: (String) -> Bool = { [weak self] number in
|
||||||
let font = Font.with(size: 20.0, design: .monospace, traits: [])
|
guard let strongSelf = self else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if let (country, _) = AuthorizationSequenceCountrySelectionController.lookupCountryIdByNumber(number, preferredCountries: strongSelf.preferredCountryIdForCode) {
|
||||||
|
let flagString = emojiFlagForISOCountryCode(country.id)
|
||||||
|
let localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(country.id, strings: strongSelf.strings) ?? country.name
|
||||||
|
strongSelf.countryButton.setTitle("\(flagString) \(localizedName)", with: Font.regular(20.0), with: theme.list.itemPrimaryTextColor, for: [])
|
||||||
|
|
||||||
|
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
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let code = Int(code), let name = name, let countryName = countryCodeAndIdToName[CountryCodeAndId(code: code, id: name)] {
|
let _ = processNumberChange(strongSelf.phoneInputNode.number)
|
||||||
let flagString = emojiFlagForISOCountryCode(name as NSString)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.phoneInputNode.countryCodeUpdated = { [weak self] code, name in
|
||||||
|
if let strongSelf = self {
|
||||||
|
if let name = name {
|
||||||
|
strongSelf.preferredCountryIdForCode[code] = name
|
||||||
|
}
|
||||||
|
|
||||||
|
if processNumberChange(strongSelf.phoneInputNode.number) {
|
||||||
|
} else if let code = Int(code), let name = name, let countryName = countryCodeAndIdToName[CountryCodeAndId(code: code, id: name)] {
|
||||||
|
let flagString = emojiFlagForISOCountryCode(name)
|
||||||
let localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(name, strings: strongSelf.strings) ?? countryName
|
let localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(name, strings: strongSelf.strings) ?? countryName
|
||||||
strongSelf.countryButton.setTitle("\(flagString) \(localizedName)", with: Font.regular(20.0), with: theme.list.itemPrimaryTextColor, for: [])
|
strongSelf.countryButton.setTitle("\(flagString) \(localizedName)", with: Font.regular(20.0), with: theme.list.itemPrimaryTextColor, for: [])
|
||||||
|
strongSelf.phoneInputNode.numberField.textField.attributedPlaceholder = NSAttributedString(string: strings.Login_PhonePlaceholder, font: Font.regular(20.0), textColor: theme.list.itemPlaceholderTextColor)
|
||||||
strongSelf.phoneInputNode.mask = AuthorizationSequenceCountrySelectionController.lookupPatternByCode(code).flatMap { NSAttributedString(string: $0, font: font, textColor: theme.list.itemPlaceholderTextColor) }
|
|
||||||
} else if let code = Int(code), let (countryId, countryName) = countryCodeToIdAndName[code] {
|
} else if let code = Int(code), let (countryId, countryName) = countryCodeToIdAndName[code] {
|
||||||
let flagString = emojiFlagForISOCountryCode(countryId as NSString)
|
let flagString = emojiFlagForISOCountryCode(countryId)
|
||||||
let localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(countryId, strings: strongSelf.strings) ?? countryName
|
let localizedName: String = AuthorizationSequenceCountrySelectionController.lookupCountryNameById(countryId, strings: strongSelf.strings) ?? countryName
|
||||||
strongSelf.countryButton.setTitle("\(flagString) \(localizedName)", with: Font.regular(20.0), with: theme.list.itemPrimaryTextColor, for: [])
|
strongSelf.countryButton.setTitle("\(flagString) \(localizedName)", with: Font.regular(20.0), with: theme.list.itemPrimaryTextColor, for: [])
|
||||||
|
strongSelf.phoneInputNode.numberField.textField.attributedPlaceholder = NSAttributedString(string: strings.Login_PhonePlaceholder, font: Font.regular(20.0), textColor: theme.list.itemPlaceholderTextColor)
|
||||||
strongSelf.phoneInputNode.mask = AuthorizationSequenceCountrySelectionController.lookupPatternByCode(code).flatMap { NSAttributedString(string: $0, font: font, textColor: theme.list.itemPlaceholderTextColor) }
|
|
||||||
} else {
|
} else {
|
||||||
strongSelf.countryButton.setTitle(strings.Login_SelectCountry_Title, with: Font.regular(20.0), with: theme.list.itemPlaceholderTextColor, for: [])
|
strongSelf.countryButton.setTitle(strings.Login_SelectCountry_Title, with: Font.regular(20.0), with: theme.list.itemPlaceholderTextColor, for: [])
|
||||||
|
|
||||||
strongSelf.phoneInputNode.mask = nil
|
strongSelf.phoneInputNode.mask = nil
|
||||||
|
strongSelf.phoneInputNode.numberField.textField.attributedPlaceholder = NSAttributedString(string: strings.Login_PhonePlaceholder, font: Font.regular(20.0), textColor: theme.list.itemPlaceholderTextColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.phoneInputNode.customFormatter = { number in
|
||||||
|
if let (_, code) = AuthorizationSequenceCountrySelectionController.lookupCountryIdByNumber(number, preferredCountries: [:]) {
|
||||||
|
return code.code
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.phoneInputNode.number = "+1"
|
self.phoneInputNode.number = "+1"
|
||||||
self.phoneInputNode.returnAction = { [weak self] in
|
self.phoneInputNode.returnAction = { [weak self] in
|
||||||
self?.checkPhone?()
|
self?.checkPhone?()
|
||||||
@ -331,6 +352,10 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateCountryCode() {
|
||||||
|
self.phoneAndCountryNode.phoneInputNode.codeAndNumber = self.codeAndNumber
|
||||||
|
}
|
||||||
|
|
||||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
var insets = layout.insets(options: [])
|
var insets = layout.insets(options: [])
|
||||||
insets.top = navigationBarHeight
|
insets.top = navigationBarHeight
|
||||||
|
@ -85,7 +85,7 @@ func presentedLegacyCamera(context: AccountContext, peer: Peer, cameraView: TGAt
|
|||||||
if peer is TelegramUser {
|
if peer is TelegramUser {
|
||||||
controller.hasTimer = hasSchedule
|
controller.hasTimer = hasSchedule
|
||||||
}
|
}
|
||||||
controller.hasSilentPosting = !isSecretChat
|
controller.hasSilentPosting = true
|
||||||
}
|
}
|
||||||
controller.hasSchedule = hasSchedule
|
controller.hasSchedule = hasSchedule
|
||||||
controller.reminder = peer.id == context.account.peerId
|
controller.reminder = peer.id == context.account.peerId
|
||||||
|
@ -337,7 +337,7 @@ public final class OngoingCallVideoCapturer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func switchVideoInput(isFront: Bool) {
|
public func switchVideoInput(isFront: Bool) {
|
||||||
self.impl.switchVideoInput(isFront)
|
self.impl.switchVideoInput(isFront ? "" : "back")
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeOutgoingVideoView(completion: @escaping (OngoingCallContextPresentationCallVideoView?) -> Void) {
|
public func makeOutgoingVideoView(completion: @escaping (OngoingCallContextPresentationCallVideoView?) -> Void) {
|
||||||
|
@ -102,14 +102,16 @@ typedef NS_ENUM(int32_t, OngoingCallDataSavingWebrtc) {
|
|||||||
- (void)setOnIsMirroredUpdated:(void (^ _Nullable)(bool))onIsMirroredUpdated;
|
- (void)setOnIsMirroredUpdated:(void (^ _Nullable)(bool))onIsMirroredUpdated;
|
||||||
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
|
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
|
||||||
- (void)setVideoContentMode:(CALayerContentsGravity _Nonnull )mode;
|
- (void)setVideoContentMode:(CALayerContentsGravity _Nonnull )mode;
|
||||||
|
- (void)setForceMirrored:(bool)forceMirrored;
|
||||||
#endif
|
#endif
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface OngoingCallThreadLocalContextVideoCapturer : NSObject
|
@interface OngoingCallThreadLocalContextVideoCapturer : NSObject
|
||||||
|
|
||||||
- (instancetype _Nonnull)init;
|
- (instancetype _Nonnull)init;
|
||||||
|
- (instancetype _Nonnull)initWithDeviceId:(NSString * _Nonnull)deviceId;
|
||||||
|
|
||||||
- (void)switchVideoInput:(bool)isFront;
|
- (void)switchVideoInput:(NSString * _Nonnull)deviceId;
|
||||||
- (void)setIsVideoEnabled:(bool)isVideoEnabled;
|
- (void)setIsVideoEnabled:(bool)isVideoEnabled;
|
||||||
|
|
||||||
- (void)makeOutgoingVideoView:(void (^_Nonnull)(UIView<OngoingCallThreadLocalContextWebrtcVideoView> * _Nullable))completion;
|
- (void)makeOutgoingVideoView:(void (^_Nonnull)(UIView<OngoingCallThreadLocalContextWebrtcVideoView> * _Nullable))completion;
|
||||||
@ -132,7 +134,7 @@ typedef NS_ENUM(int32_t, OngoingCallDataSavingWebrtc) {
|
|||||||
- (void)stop:(void (^_Nullable)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile))completion;
|
- (void)stop:(void (^_Nullable)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile))completion;
|
||||||
|
|
||||||
- (bool)needRate;
|
- (bool)needRate;
|
||||||
|
|
||||||
- (NSString * _Nullable)debugInfo;
|
- (NSString * _Nullable)debugInfo;
|
||||||
- (NSString * _Nullable)version;
|
- (NSString * _Nullable)version;
|
||||||
- (NSData * _Nonnull)getDerivedState;
|
- (NSData * _Nonnull)getDerivedState;
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
#ifndef WEBRTC_IOS
|
#ifndef WEBRTC_IOS
|
||||||
#import "platform/darwin/VideoMetalViewMac.h"
|
#import "platform/darwin/VideoMetalViewMac.h"
|
||||||
#define GLVideoView VideoMetalView
|
#import "platform/darwin/GLVideoViewMac.h"
|
||||||
#define UIViewContentModeScaleAspectFill kCAGravityResizeAspectFill
|
#define UIViewContentModeScaleAspectFill kCAGravityResizeAspectFill
|
||||||
#define UIViewContentModeScaleAspect kCAGravityResizeAspect
|
#define UIViewContentModeScaleAspect kCAGravityResizeAspect
|
||||||
|
|
||||||
@ -142,18 +142,23 @@
|
|||||||
@implementation OngoingCallThreadLocalContextVideoCapturer
|
@implementation OngoingCallThreadLocalContextVideoCapturer
|
||||||
|
|
||||||
- (instancetype _Nonnull)init {
|
- (instancetype _Nonnull)init {
|
||||||
|
return [self initWithDeviceId:@""];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype _Nonnull)initWithDeviceId:(NSString * _Nonnull)deviceId {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
_interface = tgcalls::VideoCaptureInterface::Create();
|
_interface = tgcalls::VideoCaptureInterface::Create(deviceId.UTF8String);
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)switchVideoInput:(bool)isFront {
|
- (void)switchVideoInput:(NSString * _Nonnull)deviceId {
|
||||||
_interface->switchToDevice(isFront ? "" : "back");
|
_interface->switchToDevice(deviceId.UTF8String);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setIsVideoEnabled:(bool)isVideoEnabled {
|
- (void)setIsVideoEnabled:(bool)isVideoEnabled {
|
||||||
@ -210,7 +215,7 @@
|
|||||||
NSString *_version;
|
NSString *_version;
|
||||||
id<OngoingCallThreadLocalContextQueueWebrtc> _queue;
|
id<OngoingCallThreadLocalContextQueueWebrtc> _queue;
|
||||||
int32_t _contextId;
|
int32_t _contextId;
|
||||||
|
|
||||||
OngoingCallNetworkTypeWebrtc _networkType;
|
OngoingCallNetworkTypeWebrtc _networkType;
|
||||||
NSTimeInterval _callReceiveTimeout;
|
NSTimeInterval _callReceiveTimeout;
|
||||||
NSTimeInterval _callRingTimeout;
|
NSTimeInterval _callRingTimeout;
|
||||||
@ -260,29 +265,29 @@
|
|||||||
|
|
||||||
static tgcalls::NetworkType callControllerNetworkTypeForType(OngoingCallNetworkTypeWebrtc type) {
|
static tgcalls::NetworkType callControllerNetworkTypeForType(OngoingCallNetworkTypeWebrtc type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OngoingCallNetworkTypeWifi:
|
case OngoingCallNetworkTypeWifi:
|
||||||
return tgcalls::NetworkType::WiFi;
|
return tgcalls::NetworkType::WiFi;
|
||||||
case OngoingCallNetworkTypeCellularGprs:
|
case OngoingCallNetworkTypeCellularGprs:
|
||||||
return tgcalls::NetworkType::Gprs;
|
return tgcalls::NetworkType::Gprs;
|
||||||
case OngoingCallNetworkTypeCellular3g:
|
case OngoingCallNetworkTypeCellular3g:
|
||||||
return tgcalls::NetworkType::ThirdGeneration;
|
return tgcalls::NetworkType::ThirdGeneration;
|
||||||
case OngoingCallNetworkTypeCellularLte:
|
case OngoingCallNetworkTypeCellularLte:
|
||||||
return tgcalls::NetworkType::Lte;
|
return tgcalls::NetworkType::Lte;
|
||||||
default:
|
default:
|
||||||
return tgcalls::NetworkType::ThirdGeneration;
|
return tgcalls::NetworkType::ThirdGeneration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static tgcalls::DataSaving callControllerDataSavingForType(OngoingCallDataSavingWebrtc type) {
|
static tgcalls::DataSaving callControllerDataSavingForType(OngoingCallDataSavingWebrtc type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case OngoingCallDataSavingNever:
|
case OngoingCallDataSavingNever:
|
||||||
return tgcalls::DataSaving::Never;
|
return tgcalls::DataSaving::Never;
|
||||||
case OngoingCallDataSavingCellular:
|
case OngoingCallDataSavingCellular:
|
||||||
return tgcalls::DataSaving::Mobile;
|
return tgcalls::DataSaving::Mobile;
|
||||||
case OngoingCallDataSavingAlways:
|
case OngoingCallDataSavingAlways:
|
||||||
return tgcalls::DataSaving::Always;
|
return tgcalls::DataSaving::Always;
|
||||||
default:
|
default:
|
||||||
return tgcalls::DataSaving::Never;
|
return tgcalls::DataSaving::Never;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -706,11 +711,11 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
|
|||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
if ([VideoMetalView isSupported]) {
|
if ([VideoMetalView isSupported]) {
|
||||||
VideoMetalView *remoteRenderer = [[VideoMetalView alloc] initWithFrame:CGRectZero];
|
VideoMetalView *remoteRenderer = [[VideoMetalView alloc] initWithFrame:CGRectZero];
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
remoteRenderer.videoContentMode = UIViewContentModeScaleToFill;
|
remoteRenderer.videoContentMode = UIViewContentModeScaleToFill;
|
||||||
#else
|
#else
|
||||||
remoteRenderer.videoContentMode = UIViewContentModeScaleAspect;
|
remoteRenderer.videoContentMode = UIViewContentModeScaleAspect;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> sink = [remoteRenderer getSink];
|
std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> sink = [remoteRenderer getSink];
|
||||||
__strong OngoingCallThreadLocalContextWebrtc *strongSelf = weakSelf;
|
__strong OngoingCallThreadLocalContextWebrtc *strongSelf = weakSelf;
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit b906b5a955f1e6e195cb91c4513d4cb7b3620ea6
|
Subproject commit d8b106c94e5a5e20020ad862d835e921d4f102d9
|
2
third-party/libvpx/libvpx
vendored
2
third-party/libvpx/libvpx
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 2d20a42ab60f8fed37612361f2ea776d0bc7ca1a
|
Subproject commit c413c8f18eb1932b100850505031980e27160d5f
|
Loading…
x
Reference in New Issue
Block a user