mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-03 21:16:35 +00:00
Merge commit '083e9236109a5a61dfef75070d204ff9e1a9c9f8'
This commit is contained in:
commit
c0789dffda
@ -10,18 +10,33 @@ struct MatchingDeviceContact {
|
|||||||
let firstName: String
|
let firstName: String
|
||||||
let lastName: String
|
let lastName: String
|
||||||
let phoneNumbers: [String]
|
let phoneNumbers: [String]
|
||||||
|
let peerId: PeerId?
|
||||||
}
|
}
|
||||||
|
|
||||||
enum IntentContactsError {
|
enum IntentContactsError {
|
||||||
case generic
|
case generic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let phonebookUsernamePathPrefix = "@id"
|
||||||
|
private let phonebookUsernamePrefix = "https://t.me/" + phonebookUsernamePathPrefix
|
||||||
|
|
||||||
|
private func parseAppSpecificContactReference(_ value: String) -> PeerId? {
|
||||||
|
if !value.hasPrefix(phonebookUsernamePrefix) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let idString = String(value[value.index(value.startIndex, offsetBy: phonebookUsernamePrefix.count)...])
|
||||||
|
if let id = Int32(idString) {
|
||||||
|
return PeerId(namespace: Namespaces.Peer.CloudUser, id: id)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func matchingDeviceContacts(stableIds: [String]) -> Signal<[MatchingDeviceContact], IntentContactsError> {
|
func matchingDeviceContacts(stableIds: [String]) -> Signal<[MatchingDeviceContact], IntentContactsError> {
|
||||||
guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else {
|
guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else {
|
||||||
return .fail(.generic)
|
return .fail(.generic)
|
||||||
}
|
}
|
||||||
let store = CNContactStore()
|
let store = CNContactStore()
|
||||||
guard let contacts = try? store.unifiedContacts(matching: CNContact.predicateForContacts(withIdentifiers: stableIds), keysToFetch: [CNContactFormatter.descriptorForRequiredKeys(for: .fullName), CNContactPhoneNumbersKey as CNKeyDescriptor]) else {
|
guard let contacts = try? store.unifiedContacts(matching: CNContact.predicateForContacts(withIdentifiers: stableIds), keysToFetch: [CNContactFormatter.descriptorForRequiredKeys(for: .fullName), CNContactPhoneNumbersKey as CNKeyDescriptor, CNContactUrlAddressesKey as CNKeyDescriptor]) else {
|
||||||
return .fail(.generic)
|
return .fail(.generic)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +49,14 @@ func matchingDeviceContacts(stableIds: [String]) -> Signal<[MatchingDeviceContac
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return MatchingDeviceContact(stableId: contact.identifier, firstName: contact.givenName, lastName: contact.familyName, phoneNumbers: phoneNumbers)
|
var contactPeerId: PeerId?
|
||||||
|
for address in contact.urlAddresses {
|
||||||
|
if address.label == "Telegram", let peerId = parseAppSpecificContactReference(address.value as String) {
|
||||||
|
contactPeerId = peerId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MatchingDeviceContact(stableId: contact.identifier, firstName: contact.givenName, lastName: contact.familyName, phoneNumbers: phoneNumbers, peerId: contactPeerId)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,44 +74,24 @@ func matchingCloudContacts(postbox: Postbox, contacts: [MatchingDeviceContact])
|
|||||||
return postbox.transaction { transaction -> [(String, TelegramUser)] in
|
return postbox.transaction { transaction -> [(String, TelegramUser)] in
|
||||||
var result: [(String, TelegramUser)] = []
|
var result: [(String, TelegramUser)] = []
|
||||||
outer: for peerId in transaction.getContactPeerIds() {
|
outer: for peerId in transaction.getContactPeerIds() {
|
||||||
if let peer = transaction.getPeer(peerId) as? TelegramUser, let peerPhoneNumber = peer.phone {
|
if let peer = transaction.getPeer(peerId) as? TelegramUser {
|
||||||
for contact in contacts {
|
if let peerPhoneNumber = peer.phone {
|
||||||
for phoneNumber in contact.phoneNumbers {
|
for contact in contacts {
|
||||||
if matchPhoneNumbers(phoneNumber, peerPhoneNumber) {
|
for phoneNumber in contact.phoneNumbers {
|
||||||
|
if matchPhoneNumbers(phoneNumber, peerPhoneNumber) {
|
||||||
|
result.append((contact.stableId, peer))
|
||||||
|
continue outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for contact in contacts {
|
||||||
|
if let contactPeerId = contact.peerId, contactPeerId == peerId {
|
||||||
result.append((contact.stableId, peer))
|
result.append((contact.stableId, peer))
|
||||||
continue outer
|
continue outer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// var parsedPhoneNumbers: [String: ParsedPhoneNumber] = [:]
|
|
||||||
// let parsedPeerPhoneNumber: ParsedPhoneNumber?
|
|
||||||
// if let number = parsedPhoneNumbers[peerPhoneNumber] {
|
|
||||||
// parsedPeerPhoneNumber = number
|
|
||||||
// } else if let number = ParsedPhoneNumber(string: peerPhoneNumber) {
|
|
||||||
// parsedPeerPhoneNumber = number
|
|
||||||
// parsedPhoneNumbers[peerPhoneNumber] = number
|
|
||||||
// } else {
|
|
||||||
// parsedPeerPhoneNumber = nil
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// for contact in contacts {
|
|
||||||
// for phoneNumber in contact.phoneNumbers {
|
|
||||||
// let parsedPhoneNumber: ParsedPhoneNumber?
|
|
||||||
// if let number = parsedPhoneNumbers[phoneNumber] {
|
|
||||||
// parsedPhoneNumber = number
|
|
||||||
// } else if let number = ParsedPhoneNumber(string: phoneNumber) {
|
|
||||||
// parsedPhoneNumber = number
|
|
||||||
// parsedPhoneNumbers[phoneNumber] = number
|
|
||||||
// } else {
|
|
||||||
// parsedPhoneNumber = nil
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if parsedPeerPhoneNumber == parsedPhoneNumber {
|
|
||||||
// result.append((contact.stableId, peer))
|
|
||||||
// continue outer
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
@ -110,5 +112,14 @@ func personWithUser(stableId: String, user: TelegramUser) -> INPerson {
|
|||||||
var nameComponents = PersonNameComponents()
|
var nameComponents = PersonNameComponents()
|
||||||
nameComponents.givenName = user.firstName
|
nameComponents.givenName = user.firstName
|
||||||
nameComponents.familyName = user.lastName
|
nameComponents.familyName = user.lastName
|
||||||
return INPerson(personHandle: INPersonHandle(value: stableId, type: .unknown), nameComponents: nameComponents, displayName: user.debugDisplayTitle, image: nil, contactIdentifier: stableId, customIdentifier: "tg\(user.id.toInt64())")
|
let personHandle: INPersonHandle
|
||||||
|
if let phone = user.phone {
|
||||||
|
personHandle = INPersonHandle(value: formatPhoneNumber(phone), type: .phoneNumber)
|
||||||
|
} else if let username = user.username {
|
||||||
|
personHandle = INPersonHandle(value: "@\(username)", type: .unknown)
|
||||||
|
} else {
|
||||||
|
personHandle = INPersonHandle(value: user.displayTitle, type: .unknown)
|
||||||
|
}
|
||||||
|
|
||||||
|
return INPerson(personHandle: personHandle, nameComponents: nameComponents, displayName: user.debugDisplayTitle, image: nil, contactIdentifier: stableId, customIdentifier: "tg\(user.id.toInt64())")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -202,11 +202,6 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if filteredPersons.count > 1 {
|
|
||||||
completion([.disambiguation(filteredPersons)])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var allPersonsAlreadyMatched = true
|
var allPersonsAlreadyMatched = true
|
||||||
for person in filteredPersons {
|
for person in filteredPersons {
|
||||||
if !(person.customIdentifier ?? "").hasPrefix("tg") {
|
if !(person.customIdentifier ?? "").hasPrefix("tg") {
|
||||||
@ -215,7 +210,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if allPersonsAlreadyMatched {
|
if allPersonsAlreadyMatched && filteredPersons.count == 1 {
|
||||||
completion([.success(filteredPersons[0])])
|
completion([.success(filteredPersons[0])])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -239,29 +234,31 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
|||||||
let account = self.accountPromise.get()
|
let account = self.accountPromise.get()
|
||||||
|
|
||||||
let signal = matchingDeviceContacts(stableIds: stableIds)
|
let signal = matchingDeviceContacts(stableIds: stableIds)
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> mapToSignal { matchedContacts in
|
|> mapToSignal { matchedContacts in
|
||||||
return account
|
return account
|
||||||
|> introduceError(IntentContactsError.self)
|
|> introduceError(IntentContactsError.self)
|
||||||
|> mapToSignal { account -> Signal<[(String, TelegramUser)], IntentContactsError> in
|
|> mapToSignal { account -> Signal<[(String, TelegramUser)], IntentContactsError> in
|
||||||
if let account = account {
|
if let account = account {
|
||||||
return matchingCloudContacts(postbox: account.postbox, contacts: matchedContacts)
|
return matchingCloudContacts(postbox: account.postbox, contacts: matchedContacts)
|
||||||
|> introduceError(IntentContactsError.self)
|
|> introduceError(IntentContactsError.self)
|
||||||
} else {
|
} else {
|
||||||
return .fail(.generic)
|
return .fail(.generic)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.resolvePersonsDisposable.set((signal
|
self.resolvePersonsDisposable.set((signal
|
||||||
|> deliverOnMainQueue).start(next: { peers in
|
|> deliverOnMainQueue).start(next: { peers in
|
||||||
if peers.isEmpty {
|
if peers.isEmpty {
|
||||||
completion([.needsValue])
|
completion([.noResult])
|
||||||
} else {
|
} else if peers.count == 1 {
|
||||||
completion(peers.map { .success(personWithUser(stableId: $0, user: $1)) })
|
completion(peers.map { .success(personWithUser(stableId: $0, user: $1)) })
|
||||||
}
|
} else {
|
||||||
}, error: { error in
|
completion([.disambiguation(peers.map { (personWithUser(stableId: $0, user: $1)) })])
|
||||||
completion([.skip])
|
}
|
||||||
}))
|
}, error: { error in
|
||||||
|
completion([.skip])
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - INSendMessageIntentHandling
|
// MARK: - INSendMessageIntentHandling
|
||||||
|
|||||||
104
Telegram-iOS.xcworkspace/contents.xcworkspacedata
generated
104
Telegram-iOS.xcworkspace/contents.xcworkspacedata
generated
@ -1,9 +1,28 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Workspace
|
<Workspace
|
||||||
version = "1.0">
|
version = "1.0">
|
||||||
|
<Group
|
||||||
|
location = "container:"
|
||||||
|
name = "Third Party">
|
||||||
|
<FileRef
|
||||||
|
location = "group:submodules/lottie-ios/Lottie_Xcode.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:submodules/webp/WebP_Xcode.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:submodules/HockeySDK-iOS/Support/HockeySDK_Xcode.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:submodules/ffmpeg/FFMpeg_Xcode.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Group>
|
||||||
<Group
|
<Group
|
||||||
location = "container:"
|
location = "container:"
|
||||||
name = "Utils">
|
name = "Utils">
|
||||||
|
<FileRef
|
||||||
|
location = "group:submodules/SSignalKit/SSignalKit_Xcode.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:submodules/TemporaryCachedPeerDataManager/TemporaryCachedPeerDataManager_Xcode.xcodeproj">
|
location = "group:submodules/TemporaryCachedPeerDataManager/TemporaryCachedPeerDataManager_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
@ -38,19 +57,22 @@
|
|||||||
location = "group:submodules/SaveToCameraRoll/SaveToCameraRoll_Xcode.xcodeproj">
|
location = "group:submodules/SaveToCameraRoll/SaveToCameraRoll_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/TelegramNotices/TelegramNotices_Xcode.xcodeproj">
|
location = "group:submodules/TelegramNotices/TelegramNotices_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/TelegramPermissions/TelegramPermissions_Xcode.xcodeproj">
|
location = "group:submodules/TelegramPermissions/TelegramPermissions_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:submodules/TelegramStringFormatting/TelegramStringFormatting_Xcode.xcodeproj">
|
location = "group:submodules/TelegramStringFormatting/TelegramStringFormatting_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/WebsiteType/WebsiteType_Xcode.xcodeproj">
|
location = "group:submodules/WebsiteType/WebsiteType_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/ScreenCaptureDetection/ScreenCaptureDetection_Xcode.xcodeproj">
|
location = "group:submodules/ScreenCaptureDetection/ScreenCaptureDetection_Xcode.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:submodules/GZip/GZip_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<Group
|
<Group
|
||||||
location = "container:"
|
location = "container:"
|
||||||
@ -59,13 +81,13 @@
|
|||||||
location = "group:submodules/ImageBlur/ImageBlur_Xcode.xcodeproj">
|
location = "group:submodules/ImageBlur/ImageBlur_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/TinyThumbnail/TinyThumbnail_Xcode.xcodeproj">
|
location = "group:submodules/TinyThumbnail/TinyThumbnail_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/ImageTransparency/ImageTransparency_Xcode.xcodeproj">
|
location = "group:submodules/ImageTransparency/ImageTransparency_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/ImageCompression/ImageCompression_Xcode.xcodeproj">
|
location = "group:submodules/ImageCompression/ImageCompression_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
@ -101,6 +123,9 @@
|
|||||||
<Group
|
<Group
|
||||||
location = "container:"
|
location = "container:"
|
||||||
name = "Media">
|
name = "Media">
|
||||||
|
<FileRef
|
||||||
|
location = "group:submodules/TelegramAudio/TelegramAudio_Xcode.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
<Group
|
<Group
|
||||||
location = "container:"
|
location = "container:"
|
||||||
name = "Resources">
|
name = "Resources">
|
||||||
@ -108,7 +133,7 @@
|
|||||||
location = "group:submodules/MediaResources/MediaResources_Xcode.xcodeproj">
|
location = "group:submodules/MediaResources/MediaResources_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/PhotoResources/PhotoResources_Xcode.xcodeproj">
|
location = "group:submodules/PhotoResources/PhotoResources_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:submodules/StickerResources/StickerResources_Xcode.xcodeproj">
|
location = "group:submodules/StickerResources/StickerResources_Xcode.xcodeproj">
|
||||||
@ -135,7 +160,7 @@
|
|||||||
location = "container:"
|
location = "container:"
|
||||||
name = "Video Content">
|
name = "Video Content">
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/TelegramUniversalVideoContent/TelegramUniversalVideoContent_Xcode.xcodeproj">
|
location = "group:submodules/TelegramUniversalVideoContent/TelegramUniversalVideoContent_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
</Group>
|
</Group>
|
||||||
<Group
|
<Group
|
||||||
@ -160,23 +185,23 @@
|
|||||||
location = "group:submodules/ProgressNavigationButtonNode/ProgressNavigationButtonNode_Xcode.xcodeproj">
|
location = "group:submodules/ProgressNavigationButtonNode/ProgressNavigationButtonNode_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/PhoneInputNode/PhoneInputNode_Xcode.xcodeproj">
|
location = "group:submodules/PhoneInputNode/PhoneInputNode_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/SearchBarNode/SearchBarNode_Xcode.xcodeproj">
|
location = "group:submodules/SearchBarNode/SearchBarNode_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
</Group>
|
</Group>
|
||||||
<Group
|
<Group
|
||||||
location = "container:"
|
location = "container:"
|
||||||
name = "Gestures">
|
name = "Gestures">
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/TouchDownGesture/TouchDownGesture_Xcode.xcodeproj">
|
location = "group:submodules/TouchDownGesture/TouchDownGesture_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/SwipeToDismissGesture/SwipeToDismissGesture_Xcode.xcodeproj">
|
location = "group:submodules/SwipeToDismissGesture/SwipeToDismissGesture_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/DirectionalPanGesture/DirectionalPanGesture_Xcode.xcodeproj">
|
location = "group:submodules/DirectionalPanGesture/DirectionalPanGesture_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
</Group>
|
</Group>
|
||||||
<Group
|
<Group
|
||||||
@ -190,7 +215,7 @@
|
|||||||
location = "container:"
|
location = "container:"
|
||||||
name = "Action Sheet">
|
name = "Action Sheet">
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/DateSelectionUI/DateSelectionUI_Xcode.xcodeproj">
|
location = "group:submodules/DateSelectionUI/DateSelectionUI_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:submodules/ActionSheetPeerItem/ActionSheetPeerItem_Xcode.xcodeproj">
|
location = "group:submodules/ActionSheetPeerItem/ActionSheetPeerItem_Xcode.xcodeproj">
|
||||||
@ -226,13 +251,16 @@
|
|||||||
</FileRef>
|
</FileRef>
|
||||||
</Group>
|
</Group>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/LegacyUI/LegacyUI_Xcode.xcodeproj">
|
location = "group:submodules/LegacyComponents/LegacyComponents_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/OpenInExternalAppUI/OpenInExternalAppUI_Xcode.xcodeproj">
|
location = "group:submodules/LegacyUI/LegacyUI_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/AlertUI/AlertUI_Xcode.xcodeproj">
|
location = "group:submodules/OpenInExternalAppUI/OpenInExternalAppUI_Xcode.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:submodules/AlertUI/AlertUI_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:submodules/OverlayStatusController/OverlayStatusController_Xcode.xcodeproj">
|
location = "group:submodules/OverlayStatusController/OverlayStatusController_Xcode.xcodeproj">
|
||||||
@ -274,57 +302,33 @@
|
|||||||
location = "group:submodules/ContextUI/ContextUI_Xcode.xcodeproj">
|
location = "group:submodules/ContextUI/ContextUI_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/ComposePollUI/ComposePollUI_Xcode.xcodeproj">
|
location = "group:submodules/ComposePollUI/ComposePollUI_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/UndoUI/UndoUI_Xcode.xcodeproj">
|
location = "group:submodules/UndoUI/UndoUI_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/GameUI/GameUI_Xcode.xcodeproj">
|
location = "group:submodules/GameUI/GameUI_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/WebUI/WebUI_Xcode.xcodeproj">
|
location = "group:submodules/WebUI/WebUI_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/PassportUI/PassportUI_Xcode.xcodeproj">
|
location = "group:submodules/PassportUI/PassportUI_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/CountrySelectionUI/CountrySelectionUI_Xcode.xcodeproj">
|
location = "group:submodules/CountrySelectionUI/CountrySelectionUI_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/GalleryUI/GalleryUI_Xcode.xcodeproj">
|
location = "group:submodules/GalleryUI/GalleryUI_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:/Users/peter/build/telegram-temp/telegram-ios/submodules/PasswordSetupUI/PasswordSetupUI_Xcode.xcodeproj">
|
location = "group:submodules/PasswordSetupUI/PasswordSetupUI_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
</Group>
|
</Group>
|
||||||
<FileRef
|
|
||||||
location = "group:submodules/TelegramAudio/TelegramAudio_Xcode.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
<FileRef
|
|
||||||
location = "group:submodules/GZip/GZip_Xcode.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
<FileRef
|
|
||||||
location = "group:submodules/SSignalKit/SSignalKit_Xcode.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
<FileRef
|
|
||||||
location = "group:submodules/LegacyComponents/LegacyComponents_Xcode.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
<FileRef
|
|
||||||
location = "group:submodules/lottie-ios/Lottie_Xcode.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
<FileRef
|
|
||||||
location = "group:submodules/ffmpeg/FFMpeg_Xcode.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
<FileRef
|
|
||||||
location = "group:submodules/webp/WebP_Xcode.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:submodules/TelegramUI/TelegramUI_Xcode.xcodeproj">
|
location = "group:submodules/TelegramUI/TelegramUI_Xcode.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
|
||||||
location = "group:submodules/HockeySDK-iOS/Support/HockeySDK_Xcode.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:Telegram-iOS.xcodeproj">
|
location = "group:Telegram-iOS.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
|
|||||||
@ -401,11 +401,11 @@ public final class TextNodeLayout: NSObject {
|
|||||||
let lineRange = NSIntersectionRange(range, line.range)
|
let lineRange = NSIntersectionRange(range, line.range)
|
||||||
if lineRange.length != 0 {
|
if lineRange.length != 0 {
|
||||||
var leftOffset: CGFloat = 0.0
|
var leftOffset: CGFloat = 0.0
|
||||||
if lineRange.location != line.range.location {
|
if lineRange.location != line.range.location || line.isRTL {
|
||||||
leftOffset = floor(CTLineGetOffsetForStringIndex(line.line, lineRange.location, nil))
|
leftOffset = floor(CTLineGetOffsetForStringIndex(line.line, lineRange.location, nil))
|
||||||
}
|
}
|
||||||
var rightOffset: CGFloat = line.frame.width
|
var rightOffset: CGFloat = line.frame.width
|
||||||
if lineRange.location + lineRange.length != line.range.length {
|
if lineRange.location + lineRange.length != line.range.length || line.isRTL {
|
||||||
var secondaryOffset: CGFloat = 0.0
|
var secondaryOffset: CGFloat = 0.0
|
||||||
let rawOffset = CTLineGetOffsetForStringIndex(line.line, lineRange.location + lineRange.length, &secondaryOffset)
|
let rawOffset = CTLineGetOffsetForStringIndex(line.line, lineRange.location + lineRange.length, &secondaryOffset)
|
||||||
rightOffset = ceil(rawOffset)
|
rightOffset = ceil(rawOffset)
|
||||||
@ -417,7 +417,10 @@ public final class TextNodeLayout: NSObject {
|
|||||||
|
|
||||||
lineFrame = displayLineFrame(frame: lineFrame, isRTL: line.isRTL, boundingRect: CGRect(origin: CGPoint(), size: self.size), cutout: self.cutout)
|
lineFrame = displayLineFrame(frame: lineFrame, isRTL: line.isRTL, boundingRect: CGRect(origin: CGPoint(), size: self.size), cutout: self.cutout)
|
||||||
|
|
||||||
rects.append((lineFrame, CGRect(origin: CGPoint(x: lineFrame.minX + leftOffset + self.insets.left, y: lineFrame.minY + self.insets.top), size: CGSize(width: rightOffset - leftOffset, height: lineFrame.size.height))))
|
let width = abs(rightOffset - leftOffset)
|
||||||
|
if width > 1.0 {
|
||||||
|
rects.append((lineFrame, CGRect(origin: CGPoint(x: lineFrame.minX + (leftOffset < rightOffset ? leftOffset : rightOffset) + self.insets.left, y: lineFrame.minY + self.insets.top), size: CGSize(width: width, height: lineFrame.size.height))))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !rects.isEmpty {
|
if !rects.isEmpty {
|
||||||
|
|||||||
@ -177,7 +177,7 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
|
|||||||
}
|
}
|
||||||
|
|
||||||
let leftInset: CGFloat = 16.0 + params.leftInset
|
let leftInset: CGFloat = 16.0 + params.leftInset
|
||||||
var rightInset: CGFloat = params.rightInset
|
var rightInset: CGFloat = 16.0 + params.rightInset
|
||||||
|
|
||||||
if item.clearButton {
|
if item.clearButton {
|
||||||
rightInset += 32.0
|
rightInset += 32.0
|
||||||
@ -225,27 +225,31 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
|
|||||||
secureEntry = false
|
secureEntry = false
|
||||||
capitalizationType = capitalization ? .sentences : .none
|
capitalizationType = capitalization ? .sentences : .none
|
||||||
autocorrectionType = autocorrection ? .default : .no
|
autocorrectionType = autocorrection ? .default : .no
|
||||||
keyboardType = UIKeyboardType.default
|
keyboardType = .default
|
||||||
case .email:
|
case .email:
|
||||||
secureEntry = false
|
secureEntry = false
|
||||||
capitalizationType = .none
|
capitalizationType = .none
|
||||||
autocorrectionType = .no
|
autocorrectionType = .no
|
||||||
keyboardType = UIKeyboardType.emailAddress
|
keyboardType = .emailAddress
|
||||||
case .password:
|
case .password:
|
||||||
secureEntry = true
|
secureEntry = true
|
||||||
capitalizationType = .none
|
capitalizationType = .none
|
||||||
autocorrectionType = .no
|
autocorrectionType = .no
|
||||||
keyboardType = UIKeyboardType.default
|
keyboardType = .default
|
||||||
case .number:
|
case .number:
|
||||||
secureEntry = false
|
secureEntry = false
|
||||||
capitalizationType = .none
|
capitalizationType = .none
|
||||||
autocorrectionType = .no
|
autocorrectionType = .no
|
||||||
keyboardType = UIKeyboardType.numberPad
|
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
||||||
|
keyboardType = .asciiCapableNumberPad
|
||||||
|
} else {
|
||||||
|
keyboardType = .numberPad
|
||||||
|
}
|
||||||
case .username:
|
case .username:
|
||||||
secureEntry = false
|
secureEntry = false
|
||||||
capitalizationType = .none
|
capitalizationType = .none
|
||||||
autocorrectionType = .no
|
autocorrectionType = .no
|
||||||
keyboardType = UIKeyboardType.asciiCapable
|
keyboardType = .asciiCapable
|
||||||
}
|
}
|
||||||
|
|
||||||
if strongSelf.textNode.textField.isSecureTextEntry != secureEntry {
|
if strongSelf.textNode.textField.isSecureTextEntry != secureEntry {
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
D084FA1622F436DE004874CE /* SwiftSignalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D084FA1522F436DE004874CE /* SwiftSignalKit.framework */; };
|
D084FA1622F436DE004874CE /* SwiftSignalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D084FA1522F436DE004874CE /* SwiftSignalKit.framework */; };
|
||||||
D0C9C0D322FE3E7500FAB518 /* MapResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C9C0D222FE3E7500FAB518 /* MapResources.swift */; };
|
D0C9C0D322FE3E7500FAB518 /* MapResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C9C0D222FE3E7500FAB518 /* MapResources.swift */; };
|
||||||
D0C9C0D522FE3E8200FAB518 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C9C0D422FE3E8200FAB518 /* MapKit.framework */; };
|
D0C9C0D522FE3E8200FAB518 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C9C0D422FE3E8200FAB518 /* MapKit.framework */; };
|
||||||
|
D0C9C5342301CC5100FAB518 /* TelegramCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C9C5332301CC5100FAB518 /* TelegramCore.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
@ -28,6 +29,7 @@
|
|||||||
D084FA1522F436DE004874CE /* SwiftSignalKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SwiftSignalKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
D084FA1522F436DE004874CE /* SwiftSignalKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SwiftSignalKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D0C9C0D222FE3E7500FAB518 /* MapResources.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapResources.swift; sourceTree = "<group>"; };
|
D0C9C0D222FE3E7500FAB518 /* MapResources.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapResources.swift; sourceTree = "<group>"; };
|
||||||
D0C9C0D422FE3E8200FAB518 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; };
|
D0C9C0D422FE3E8200FAB518 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; };
|
||||||
|
D0C9C5332301CC5100FAB518 /* TelegramCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = TelegramCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -35,6 +37,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
D0C9C5342301CC5100FAB518 /* TelegramCore.framework in Frameworks */,
|
||||||
D0C9C0D522FE3E8200FAB518 /* MapKit.framework in Frameworks */,
|
D0C9C0D522FE3E8200FAB518 /* MapKit.framework in Frameworks */,
|
||||||
D084FA1622F436DE004874CE /* SwiftSignalKit.framework in Frameworks */,
|
D084FA1622F436DE004874CE /* SwiftSignalKit.framework in Frameworks */,
|
||||||
D084FA1422F436DA004874CE /* Postbox.framework in Frameworks */,
|
D084FA1422F436DA004874CE /* Postbox.framework in Frameworks */,
|
||||||
@ -77,6 +80,7 @@
|
|||||||
D084FA0E22F436D2004874CE /* Frameworks */ = {
|
D084FA0E22F436D2004874CE /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D0C9C5332301CC5100FAB518 /* TelegramCore.framework */,
|
||||||
D0C9C0D422FE3E8200FAB518 /* MapKit.framework */,
|
D0C9C0D422FE3E8200FAB518 /* MapKit.framework */,
|
||||||
D084FA1522F436DE004874CE /* SwiftSignalKit.framework */,
|
D084FA1522F436DE004874CE /* SwiftSignalKit.framework */,
|
||||||
D084FA1322F436DA004874CE /* Postbox.framework */,
|
D084FA1322F436DA004874CE /* Postbox.framework */,
|
||||||
|
|||||||
@ -225,6 +225,8 @@ static NSData *base64_decode(NSString *str) {
|
|||||||
if (hexData == nil) {
|
if (hexData == nil) {
|
||||||
NSString *finalString = @"";
|
NSString *finalString = @"";
|
||||||
finalString = [finalString stringByAppendingString:[string stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]]];
|
finalString = [finalString stringByAppendingString:[string stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]]];
|
||||||
|
finalString = [finalString stringByReplacingOccurrencesOfString:@"-" withString:@"+"];
|
||||||
|
finalString = [finalString stringByReplacingOccurrencesOfString:@"_" withString:@"/"];
|
||||||
while (finalString.length % 4 != 0) {
|
while (finalString.length % 4 != 0) {
|
||||||
finalString = [finalString stringByAppendingString:@"="];
|
finalString = [finalString stringByAppendingString:@"="];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -123,7 +123,11 @@ final class FormControllerTextInputItemNode: FormBlockItemNode<FormControllerTex
|
|||||||
case .number:
|
case .number:
|
||||||
capitalizationType = .none
|
capitalizationType = .none
|
||||||
autocorrectionType = .no
|
autocorrectionType = .no
|
||||||
keyboardType = .numberPad
|
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
||||||
|
keyboardType = .asciiCapableNumberPad
|
||||||
|
} else {
|
||||||
|
keyboardType = .numberPad
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.textField.textField.keyboardType != keyboardType {
|
if self.textField.textField.keyboardType != keyboardType {
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
D0C9C5272300EF9900FAB518 /* ActivityIndicator.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C9C5262300EF9900FAB518 /* ActivityIndicator.framework */; };
|
D0C9C5272300EF9900FAB518 /* ActivityIndicator.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C9C5262300EF9900FAB518 /* ActivityIndicator.framework */; };
|
||||||
D0C9C5292300EF9E00FAB518 /* AlertUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C9C5282300EF9E00FAB518 /* AlertUI.framework */; };
|
D0C9C5292300EF9E00FAB518 /* AlertUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C9C5282300EF9E00FAB518 /* AlertUI.framework */; };
|
||||||
D0C9C52F2300F01C00FAB518 /* ResetPasswordController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C9C52E2300F01C00FAB518 /* ResetPasswordController.swift */; };
|
D0C9C52F2300F01C00FAB518 /* ResetPasswordController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C9C52E2300F01C00FAB518 /* ResetPasswordController.swift */; };
|
||||||
|
D0C9C5382301CCE200FAB518 /* ItemListUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C9C5372301CCE200FAB518 /* ItemListUI.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
@ -46,6 +47,7 @@
|
|||||||
D0C9C5262300EF9900FAB518 /* ActivityIndicator.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ActivityIndicator.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
D0C9C5262300EF9900FAB518 /* ActivityIndicator.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ActivityIndicator.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D0C9C5282300EF9E00FAB518 /* AlertUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AlertUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
D0C9C5282300EF9E00FAB518 /* AlertUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AlertUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
D0C9C52E2300F01C00FAB518 /* ResetPasswordController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResetPasswordController.swift; sourceTree = "<group>"; };
|
D0C9C52E2300F01C00FAB518 /* ResetPasswordController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResetPasswordController.swift; sourceTree = "<group>"; };
|
||||||
|
D0C9C5372301CCE200FAB518 /* ItemListUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ItemListUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -53,6 +55,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
D0C9C5382301CCE200FAB518 /* ItemListUI.framework in Frameworks */,
|
||||||
D0C9C5292300EF9E00FAB518 /* AlertUI.framework in Frameworks */,
|
D0C9C5292300EF9E00FAB518 /* AlertUI.framework in Frameworks */,
|
||||||
D0C9C5272300EF9900FAB518 /* ActivityIndicator.framework in Frameworks */,
|
D0C9C5272300EF9900FAB518 /* ActivityIndicator.framework in Frameworks */,
|
||||||
D0C9C5252300EF8E00FAB518 /* AccountContext.framework in Frameworks */,
|
D0C9C5252300EF8E00FAB518 /* AccountContext.framework in Frameworks */,
|
||||||
@ -104,6 +107,7 @@
|
|||||||
D0C9C5112300EF5300FAB518 /* Frameworks */ = {
|
D0C9C5112300EF5300FAB518 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D0C9C5372301CCE200FAB518 /* ItemListUI.framework */,
|
||||||
D0C9C5282300EF9E00FAB518 /* AlertUI.framework */,
|
D0C9C5282300EF9E00FAB518 /* AlertUI.framework */,
|
||||||
D0C9C5262300EF9900FAB518 /* ActivityIndicator.framework */,
|
D0C9C5262300EF9900FAB518 /* ActivityIndicator.framework */,
|
||||||
D0C9C5242300EF8E00FAB518 /* AccountContext.framework */,
|
D0C9C5242300EF8E00FAB518 /* AccountContext.framework */,
|
||||||
|
|||||||
@ -73,7 +73,11 @@ final class SetupTwoStepVerificationContentNode: ASDisplayNode, UITextFieldDeleg
|
|||||||
case .code:
|
case .code:
|
||||||
self.inputNode.textField.autocapitalizationType = .none
|
self.inputNode.textField.autocapitalizationType = .none
|
||||||
self.inputNode.textField.autocorrectionType = .no
|
self.inputNode.textField.autocorrectionType = .no
|
||||||
self.inputNode.textField.keyboardType = .numberPad
|
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
||||||
|
self.inputNode.textField.keyboardType = .asciiCapableNumberPad
|
||||||
|
} else {
|
||||||
|
self.inputNode.textField.keyboardType = .numberPad
|
||||||
|
}
|
||||||
if #available(iOSApplicationExtension 12.0, iOS 12.0, *) {
|
if #available(iOSApplicationExtension 12.0, iOS 12.0, *) {
|
||||||
self.inputNode.textField.textContentType = .oneTimeCode
|
self.inputNode.textField.textContentType = .oneTimeCode
|
||||||
}
|
}
|
||||||
|
|||||||
@ -159,17 +159,21 @@ public final class PhoneInputNode: ASDisplayNode, UITextFieldDelegate {
|
|||||||
self.countryCodeField = TextFieldNode()
|
self.countryCodeField = TextFieldNode()
|
||||||
self.countryCodeField.textField.font = Font.regular(fontSize)
|
self.countryCodeField.textField.font = Font.regular(fontSize)
|
||||||
self.countryCodeField.textField.textAlignment = .center
|
self.countryCodeField.textField.textAlignment = .center
|
||||||
self.countryCodeField.textField.keyboardType = .numberPad
|
|
||||||
self.countryCodeField.textField.returnKeyType = .next
|
self.countryCodeField.textField.returnKeyType = .next
|
||||||
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
||||||
|
self.countryCodeField.textField.keyboardType = .asciiCapableNumberPad
|
||||||
self.countryCodeField.textField.textContentType = .telephoneNumber
|
self.countryCodeField.textField.textContentType = .telephoneNumber
|
||||||
|
} else {
|
||||||
|
self.countryCodeField.textField.keyboardType = .numberPad
|
||||||
}
|
}
|
||||||
|
|
||||||
self.numberField = TextFieldNode()
|
self.numberField = TextFieldNode()
|
||||||
self.numberField.textField.font = Font.regular(fontSize)
|
self.numberField.textField.font = Font.regular(fontSize)
|
||||||
self.numberField.textField.keyboardType = .numberPad
|
|
||||||
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
||||||
|
self.numberField.textField.keyboardType = .asciiCapableNumberPad
|
||||||
self.numberField.textField.textContentType = .telephoneNumber
|
self.numberField.textField.textContentType = .telephoneNumber
|
||||||
|
} else {
|
||||||
|
self.numberField.textField.keyboardType = .numberPad
|
||||||
}
|
}
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|||||||
@ -151,7 +151,11 @@ final class AuthorizationSequenceCodeEntryControllerNode: ASDisplayNode, UITextF
|
|||||||
self.codeField = TextFieldNode()
|
self.codeField = TextFieldNode()
|
||||||
self.codeField.textField.font = Font.regular(24.0)
|
self.codeField.textField.font = Font.regular(24.0)
|
||||||
self.codeField.textField.textAlignment = .center
|
self.codeField.textField.textAlignment = .center
|
||||||
self.codeField.textField.keyboardType = .numberPad
|
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
||||||
|
self.codeField.textField.keyboardType = .asciiCapableNumberPad
|
||||||
|
} else {
|
||||||
|
self.codeField.textField.keyboardType = .numberPad
|
||||||
|
}
|
||||||
#if swift(>=4.2)
|
#if swift(>=4.2)
|
||||||
if #available(iOSApplicationExtension 12.0, iOS 12.0, *) {
|
if #available(iOSApplicationExtension 12.0, iOS 12.0, *) {
|
||||||
self.codeField.textField.textContentType = .oneTimeCode
|
self.codeField.textField.textContentType = .oneTimeCode
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
static const char *AMQueueSpecific = "AMQueueSpecific";
|
static const char *AMQueueSpecific = "AMQueueSpecific";
|
||||||
|
|
||||||
const NSInteger TGBridgeAudioEncoderSampleRate = 16000;
|
const NSInteger TGBridgeAudioEncoderSampleRate = 48000;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ATQueuePriorityLow,
|
ATQueuePriorityLow,
|
||||||
@ -81,13 +81,13 @@ typedef enum {
|
|||||||
|
|
||||||
NSDictionary *outputSettings = @
|
NSDictionary *outputSettings = @
|
||||||
{
|
{
|
||||||
AVFormatIDKey: @(kAudioFormatLinearPCM),
|
AVFormatIDKey: @(kAudioFormatLinearPCM),
|
||||||
AVSampleRateKey: @(TGBridgeAudioEncoderSampleRate),
|
AVSampleRateKey: @(TGBridgeAudioEncoderSampleRate),
|
||||||
AVNumberOfChannelsKey: @1,
|
AVNumberOfChannelsKey: @1,
|
||||||
AVLinearPCMBitDepthKey: @16,
|
AVLinearPCMBitDepthKey: @16,
|
||||||
AVLinearPCMIsFloatKey: @false,
|
AVLinearPCMIsFloatKey: @false,
|
||||||
AVLinearPCMIsBigEndianKey: @false,
|
AVLinearPCMIsBigEndianKey: @false,
|
||||||
AVLinearPCMIsNonInterleaved: @false
|
AVLinearPCMIsNonInterleaved: @false
|
||||||
};
|
};
|
||||||
|
|
||||||
_readerOutput = [AVAssetReaderAudioMixOutput assetReaderAudioMixOutputWithAudioTracks:asset.tracks audioSettings:outputSettings];
|
_readerOutput = [AVAssetReaderAudioMixOutput assetReaderAudioMixOutputWithAudioTracks:asset.tracks audioSettings:outputSettings];
|
||||||
@ -114,9 +114,9 @@ typedef enum {
|
|||||||
static ATQueue *queue = nil;
|
static ATQueue *queue = nil;
|
||||||
static dispatch_once_t onceToken;
|
static dispatch_once_t onceToken;
|
||||||
dispatch_once(&onceToken, ^
|
dispatch_once(&onceToken, ^
|
||||||
{
|
{
|
||||||
queue = [[ATQueue alloc] initWithName:@"org.telegram.opusAudioEncoderQueue"];
|
queue = [[ATQueue alloc] initWithName:@"org.telegram.opusAudioEncoderQueue"];
|
||||||
});
|
});
|
||||||
|
|
||||||
return queue;
|
return queue;
|
||||||
}
|
}
|
||||||
@ -126,74 +126,74 @@ static const int encoderPacketSizeInBytes = TGBridgeAudioEncoderSampleRate / 100
|
|||||||
- (void)startWithCompletion:(void (^)(NSString *, int32_t))completion
|
- (void)startWithCompletion:(void (^)(NSString *, int32_t))completion
|
||||||
{
|
{
|
||||||
[[TGBridgeAudioEncoder processingQueue] dispatch:^
|
[[TGBridgeAudioEncoder processingQueue] dispatch:^
|
||||||
{
|
{
|
||||||
_oggWriter = [[TGOggOpusWriter alloc] init];
|
_oggWriter = [[TGOggOpusWriter alloc] init];
|
||||||
if (![_oggWriter beginWithDataItem:_tempFileItem])
|
if (![_oggWriter beginWithDataItem:_tempFileItem])
|
||||||
{
|
{
|
||||||
[self cleanup];
|
[self cleanup];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
[_assetReader startReading];
|
[_assetReader startReading];
|
||||||
|
|
||||||
while (_assetReader.status != AVAssetReaderStatusCompleted)
|
while (_assetReader.status != AVAssetReaderStatusCompleted)
|
||||||
{
|
{
|
||||||
if (_assetReader.status == AVAssetReaderStatusReading)
|
if (_assetReader.status == AVAssetReaderStatusReading)
|
||||||
{
|
{
|
||||||
CMSampleBufferRef nextBuffer = [_readerOutput copyNextSampleBuffer];
|
CMSampleBufferRef nextBuffer = [_readerOutput copyNextSampleBuffer];
|
||||||
if (nextBuffer)
|
if (nextBuffer)
|
||||||
{
|
{
|
||||||
AudioBufferList abl;
|
AudioBufferList abl;
|
||||||
CMBlockBufferRef blockBuffer;
|
CMBlockBufferRef blockBuffer;
|
||||||
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(nextBuffer, NULL, &abl, sizeof(abl), NULL, NULL, kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, &blockBuffer);
|
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(nextBuffer, NULL, &abl, sizeof(abl), NULL, NULL, kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, &blockBuffer);
|
||||||
|
|
||||||
[[TGBridgeAudioEncoder processingQueue] dispatch:^
|
[[TGBridgeAudioEncoder processingQueue] dispatch:^
|
||||||
{
|
{
|
||||||
[self _processBuffer:&abl.mBuffers[0]];
|
[self _processBuffer:&abl.mBuffers[0]];
|
||||||
|
|
||||||
CFRelease(nextBuffer);
|
CFRelease(nextBuffer);
|
||||||
CFRelease(blockBuffer);
|
CFRelease(blockBuffer);
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[[TGBridgeAudioEncoder processingQueue] dispatch:^
|
[[TGBridgeAudioEncoder processingQueue] dispatch:^
|
||||||
{
|
{
|
||||||
if (_tailLength > 0) {
|
if (_tailLength > 0) {
|
||||||
[_oggWriter writeFrame:(uint8_t *)_audioBuffer.bytes frameByteCount:(NSUInteger)_tailLength];
|
[_oggWriter writeFrame:(uint8_t *)_audioBuffer.bytes frameByteCount:(NSUInteger)_tailLength];
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[TGBridgeAudioEncoder processingQueue] dispatch:^
|
[[TGBridgeAudioEncoder processingQueue] dispatch:^
|
||||||
{
|
{
|
||||||
TGFileDataItem *dataItemResult = nil;
|
TGFileDataItem *dataItemResult = nil;
|
||||||
NSTimeInterval durationResult = 0.0;
|
NSTimeInterval durationResult = 0.0;
|
||||||
|
|
||||||
NSUInteger totalBytes = 0;
|
NSUInteger totalBytes = 0;
|
||||||
|
|
||||||
if (_assetReader.status == AVAssetReaderStatusCompleted)
|
if (_assetReader.status == AVAssetReaderStatusCompleted)
|
||||||
{
|
{
|
||||||
NSLog(@"finished");
|
NSLog(@"finished");
|
||||||
if (_oggWriter != nil)
|
if (_oggWriter != nil && [_oggWriter writeFrame:NULL frameByteCount:0])
|
||||||
{
|
{
|
||||||
dataItemResult = _tempFileItem;
|
dataItemResult = _tempFileItem;
|
||||||
durationResult = [_oggWriter encodedDuration];
|
durationResult = [_oggWriter encodedDuration];
|
||||||
totalBytes = [_oggWriter encodedBytes];
|
totalBytes = [_oggWriter encodedBytes];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self cleanup];
|
[self cleanup];
|
||||||
}
|
}
|
||||||
|
|
||||||
//TGLog(@"[TGBridgeAudioEncoder#%x convert time: %f ms]", self, (CFAbsoluteTimeGetCurrent() - startTime) * 1000.0);
|
//TGLog(@"[TGBridgeAudioEncoder#%x convert time: %f ms]", self, (CFAbsoluteTimeGetCurrent() - startTime) * 1000.0);
|
||||||
|
|
||||||
if (completion != nil)
|
if (completion != nil)
|
||||||
completion(dataItemResult.path, (int32_t)durationResult);
|
completion(dataItemResult.path, (int32_t)durationResult);
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_processBuffer:(AudioBuffer const *)buffer
|
- (void)_processBuffer:(AudioBuffer const *)buffer
|
||||||
@ -306,11 +306,11 @@ static const int encoderPacketSizeInBytes = TGBridgeAudioEncoderSampleRate / 100
|
|||||||
|
|
||||||
|
|
||||||
[_queue dispatch:^
|
[_queue dispatch:^
|
||||||
{
|
{
|
||||||
_fileName = filePath;
|
_fileName = filePath;
|
||||||
_length = [[[NSFileManager defaultManager] attributesOfItemAtPath:_fileName error:nil][NSFileSize] unsignedIntegerValue];
|
_length = [[[NSFileManager defaultManager] attributesOfItemAtPath:_fileName error:nil][NSFileSize] unsignedIntegerValue];
|
||||||
_fileExists = [[NSFileManager defaultManager] fileExistsAtPath:_fileName];
|
_fileExists = [[NSFileManager defaultManager] fileExistsAtPath:_fileName];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -322,38 +322,38 @@ static const int encoderPacketSizeInBytes = TGBridgeAudioEncoderSampleRate / 100
|
|||||||
- (void)moveToPath:(NSString *)path
|
- (void)moveToPath:(NSString *)path
|
||||||
{
|
{
|
||||||
[_queue dispatch:^
|
[_queue dispatch:^
|
||||||
{
|
{
|
||||||
[[NSFileManager defaultManager] moveItemAtPath:_fileName toPath:path error:nil];
|
[[NSFileManager defaultManager] moveItemAtPath:_fileName toPath:path error:nil];
|
||||||
_fileName = path;
|
_fileName = path;
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)remove
|
- (void)remove
|
||||||
{
|
{
|
||||||
[_queue dispatch:^
|
[_queue dispatch:^
|
||||||
{
|
{
|
||||||
[[NSFileManager defaultManager] removeItemAtPath:_fileName error:nil];
|
[[NSFileManager defaultManager] removeItemAtPath:_fileName error:nil];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)appendData:(NSData *)data
|
- (void)appendData:(NSData *)data
|
||||||
{
|
{
|
||||||
[_queue dispatch:^
|
[_queue dispatch:^
|
||||||
{
|
{
|
||||||
if (!_fileExists)
|
if (!_fileExists)
|
||||||
{
|
{
|
||||||
[[NSFileManager defaultManager] createFileAtPath:_fileName contents:nil attributes:nil];
|
[[NSFileManager defaultManager] createFileAtPath:_fileName contents:nil attributes:nil];
|
||||||
_fileExists = true;
|
_fileExists = true;
|
||||||
}
|
}
|
||||||
NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:_fileName];
|
NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:_fileName];
|
||||||
[file seekToEndOfFile];
|
[file seekToEndOfFile];
|
||||||
[file writeData:data];
|
[file writeData:data];
|
||||||
[file synchronizeFile];
|
[file synchronizeFile];
|
||||||
[file closeFile];
|
[file closeFile];
|
||||||
_length += data.length;
|
_length += data.length;
|
||||||
|
|
||||||
[_data appendData:data];
|
[_data appendData:data];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSData *)readDataAtOffset:(NSUInteger)offset length:(NSUInteger)length
|
- (NSData *)readDataAtOffset:(NSUInteger)offset length:(NSUInteger)length
|
||||||
@ -361,14 +361,14 @@ static const int encoderPacketSizeInBytes = TGBridgeAudioEncoderSampleRate / 100
|
|||||||
__block NSData *data = nil;
|
__block NSData *data = nil;
|
||||||
|
|
||||||
[_queue dispatch:^
|
[_queue dispatch:^
|
||||||
{
|
{
|
||||||
NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:_fileName];
|
NSFileHandle *file = [NSFileHandle fileHandleForUpdatingAtPath:_fileName];
|
||||||
[file seekToFileOffset:(unsigned long long)offset];
|
[file seekToFileOffset:(unsigned long long)offset];
|
||||||
data = [file readDataOfLength:length];
|
data = [file readDataOfLength:length];
|
||||||
if (data.length != length)
|
if (data.length != length)
|
||||||
//TGLog(@"Read data length mismatch");
|
//TGLog(@"Read data length mismatch");
|
||||||
[file closeFile];
|
[file closeFile];
|
||||||
} synchronous:true];
|
} synchronous:true];
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@ -377,9 +377,9 @@ static const int encoderPacketSizeInBytes = TGBridgeAudioEncoderSampleRate / 100
|
|||||||
{
|
{
|
||||||
__block NSUInteger result = 0;
|
__block NSUInteger result = 0;
|
||||||
[_queue dispatch:^
|
[_queue dispatch:^
|
||||||
{
|
{
|
||||||
result = _length;
|
result = _length;
|
||||||
} synchronous:true];
|
} synchronous:true];
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -420,11 +420,11 @@ static const int encoderPacketSizeInBytes = TGBridgeAudioEncoderSampleRate / 100
|
|||||||
static ATQueue *queue = nil;
|
static ATQueue *queue = nil;
|
||||||
static dispatch_once_t onceToken;
|
static dispatch_once_t onceToken;
|
||||||
dispatch_once(&onceToken, ^
|
dispatch_once(&onceToken, ^
|
||||||
{
|
{
|
||||||
queue = [[ATQueue alloc] init];
|
queue = [[ATQueue alloc] init];
|
||||||
queue->_nativeQueue = dispatch_get_main_queue();
|
queue->_nativeQueue = dispatch_get_main_queue();
|
||||||
queue->_isMainQueue = true;
|
queue->_isMainQueue = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
return queue;
|
return queue;
|
||||||
}
|
}
|
||||||
@ -434,9 +434,9 @@ static const int encoderPacketSizeInBytes = TGBridgeAudioEncoderSampleRate / 100
|
|||||||
static ATQueue *queue = nil;
|
static ATQueue *queue = nil;
|
||||||
static dispatch_once_t onceToken;
|
static dispatch_once_t onceToken;
|
||||||
dispatch_once(&onceToken, ^
|
dispatch_once(&onceToken, ^
|
||||||
{
|
{
|
||||||
queue = [[ATQueue alloc] initWithNativeQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
|
queue = [[ATQueue alloc] initWithNativeQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
|
||||||
});
|
});
|
||||||
|
|
||||||
return queue;
|
return queue;
|
||||||
}
|
}
|
||||||
@ -446,9 +446,9 @@ static const int encoderPacketSizeInBytes = TGBridgeAudioEncoderSampleRate / 100
|
|||||||
static ATQueue *queue = nil;
|
static ATQueue *queue = nil;
|
||||||
static dispatch_once_t onceToken;
|
static dispatch_once_t onceToken;
|
||||||
dispatch_once(&onceToken, ^
|
dispatch_once(&onceToken, ^
|
||||||
{
|
{
|
||||||
queue = [[ATQueue alloc] initWithNativeQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)];
|
queue = [[ATQueue alloc] initWithNativeQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)];
|
||||||
});
|
});
|
||||||
|
|
||||||
return queue;
|
return queue;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6652,7 +6652,7 @@ public final class ChatController: TelegramBaseController, GalleryHiddenMediaTar
|
|||||||
|
|
||||||
let targetRect = node.view.convert(rect, to: sourceView)
|
let targetRect = node.view.convert(rect, to: sourceView)
|
||||||
let sourceRect = CGRect(origin: CGPoint(x: floor(targetRect.midX), y: floor(targetRect.midY)), size: CGSize(width: 1.0, height: 1.0))
|
let sourceRect = CGRect(origin: CGPoint(x: floor(targetRect.midX), y: floor(targetRect.midY)), size: CGSize(width: 1.0, height: 1.0))
|
||||||
if let parsedUrl = URL(string: string) {
|
if let parsedUrl = parsedUrlValue {
|
||||||
if parsedUrl.scheme == "http" || parsedUrl.scheme == "https" {
|
if parsedUrl.scheme == "http" || parsedUrl.scheme == "https" {
|
||||||
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
|
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
|
||||||
let controller = SFSafariViewController(url: parsedUrl)
|
let controller = SFSafariViewController(url: parsedUrl)
|
||||||
|
|||||||
@ -105,8 +105,6 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDel
|
|||||||
|
|
||||||
self.pickerView.timeZone = TimeZone.current
|
self.pickerView.timeZone = TimeZone.current
|
||||||
self.pickerView.minuteInterval = 5
|
self.pickerView.minuteInterval = 5
|
||||||
self.pickerView.maximumDate = Date(timeIntervalSince1970: Double(Int32.max - 1))
|
|
||||||
|
|
||||||
self.pickerView.setValue(self.presentationData.theme.actionSheet.primaryTextColor, forKey: "textColor")
|
self.pickerView.setValue(self.presentationData.theme.actionSheet.primaryTextColor, forKey: "textColor")
|
||||||
|
|
||||||
self.contentContainerNode.view.addSubview(self.pickerView)
|
self.contentContainerNode.view.addSubview(self.pickerView)
|
||||||
@ -137,6 +135,10 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDel
|
|||||||
components.second = 0
|
components.second = 0
|
||||||
let minute = (components.minute ?? 0) % 5
|
let minute = (components.minute ?? 0) % 5
|
||||||
|
|
||||||
|
if let date = calendar.date(byAdding: .day, value: 365, to: currentDate) {
|
||||||
|
self.pickerView.maximumDate = date
|
||||||
|
}
|
||||||
|
|
||||||
if let date = calendar.date(byAdding: .minute, value: 5 - minute, to: calendar.date(from: components)!) {
|
if let date = calendar.date(byAdding: .minute, value: 5 - minute, to: calendar.date(from: components)!) {
|
||||||
self.pickerView.minimumDate = date
|
self.pickerView.minimumDate = date
|
||||||
self.pickerView.date = date
|
self.pickerView.date = date
|
||||||
|
|||||||
@ -314,7 +314,7 @@ final class ManagedAudioRecorderContext {
|
|||||||
|
|
||||||
self.idleTimerExtensionDisposable = (Signal<Void, NoError> { subscriber in
|
self.idleTimerExtensionDisposable = (Signal<Void, NoError> { subscriber in
|
||||||
return pushIdleTimerExtension()
|
return pushIdleTimerExtension()
|
||||||
} |> delay(5.0, queue: queue)).start()
|
} |> delay(5.0, queue: queue)).start()
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
@ -401,19 +401,19 @@ final class ManagedAudioRecorderContext {
|
|||||||
strongSelf.audioSessionAcquired(headset: state.isHeadsetConnected)
|
strongSelf.audioSessionAcquired(headset: state.isHeadsetConnected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, deactivate: { [weak self] in
|
}, deactivate: { [weak self] in
|
||||||
return Signal { subscriber in
|
return Signal { subscriber in
|
||||||
queue.async {
|
queue.async {
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.hasAudioSession = false
|
strongSelf.hasAudioSession = false
|
||||||
strongSelf.stop()
|
strongSelf.stop()
|
||||||
strongSelf.recordingState.set(.stopped)
|
strongSelf.recordingState.set(.stopped)
|
||||||
subscriber.putCompletion()
|
subscriber.putCompletion()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return EmptyDisposable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return EmptyDisposable
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -587,53 +587,57 @@ final class ManagedAudioRecorderContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func takeData() -> RecordedAudioData? {
|
func takeData() -> RecordedAudioData? {
|
||||||
var scaledSamplesMemory = malloc(100 * 2)!
|
if self.oggWriter.writeFrame(nil, frameByteCount: 0) {
|
||||||
var scaledSamples: UnsafeMutablePointer<Int16> = scaledSamplesMemory.assumingMemoryBound(to: Int16.self)
|
var scaledSamplesMemory = malloc(100 * 2)!
|
||||||
defer {
|
var scaledSamples: UnsafeMutablePointer<Int16> = scaledSamplesMemory.assumingMemoryBound(to: Int16.self)
|
||||||
free(scaledSamplesMemory)
|
defer {
|
||||||
}
|
free(scaledSamplesMemory)
|
||||||
memset(scaledSamples, 0, 100 * 2);
|
}
|
||||||
var waveform: Data?
|
memset(scaledSamples, 0, 100 * 2);
|
||||||
|
var waveform: Data?
|
||||||
let count = self.compressedWaveformSamples.count / 2
|
|
||||||
self.compressedWaveformSamples.withUnsafeMutableBytes { (samples: UnsafeMutablePointer<Int16>) -> Void in
|
let count = self.compressedWaveformSamples.count / 2
|
||||||
for i in 0 ..< count {
|
self.compressedWaveformSamples.withUnsafeMutableBytes { (samples: UnsafeMutablePointer<Int16>) -> Void in
|
||||||
let sample = samples[i]
|
for i in 0 ..< count {
|
||||||
let index = i * 100 / count
|
let sample = samples[i]
|
||||||
if (scaledSamples[index] < sample) {
|
let index = i * 100 / count
|
||||||
scaledSamples[index] = sample;
|
if (scaledSamples[index] < sample) {
|
||||||
|
scaledSamples[index] = sample;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
var peak: Int16 = 0
|
||||||
var peak: Int16 = 0
|
var sumSamples: Int64 = 0
|
||||||
var sumSamples: Int64 = 0
|
for i in 0 ..< 100 {
|
||||||
for i in 0 ..< 100 {
|
let sample = scaledSamples[i]
|
||||||
let sample = scaledSamples[i]
|
if peak < sample {
|
||||||
if peak < sample {
|
peak = sample
|
||||||
peak = sample
|
}
|
||||||
|
sumSamples += Int64(sample)
|
||||||
}
|
}
|
||||||
sumSamples += Int64(sample)
|
var calculatedPeak: UInt16 = 0
|
||||||
}
|
calculatedPeak = UInt16((Double(sumSamples) * 1.8 / 100.0))
|
||||||
var calculatedPeak: UInt16 = 0
|
|
||||||
calculatedPeak = UInt16((Double(sumSamples) * 1.8 / 100.0))
|
if calculatedPeak < 2500 {
|
||||||
|
calculatedPeak = 2500
|
||||||
if calculatedPeak < 2500 {
|
}
|
||||||
calculatedPeak = 2500
|
|
||||||
|
for i in 0 ..< 100 {
|
||||||
|
let sample: UInt16 = UInt16(Int64(scaledSamples[i]))
|
||||||
|
let minPeak = min(Int64(sample), Int64(calculatedPeak))
|
||||||
|
let resultPeak = minPeak * 31 / Int64(calculatedPeak)
|
||||||
|
scaledSamples[i] = Int16(clamping: min(31, resultPeak))
|
||||||
|
}
|
||||||
|
|
||||||
|
let resultWaveform = AudioWaveform(samples: Data(bytes: scaledSamplesMemory, count: 100 * 2), peak: 31)
|
||||||
|
let bitstream = resultWaveform.makeBitstream()
|
||||||
|
waveform = AudioWaveform(bitstream: bitstream, bitsPerSample: 5).makeBitstream()
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0 ..< 100 {
|
return RecordedAudioData(compressedData: self.dataItem.data(), duration: self.oggWriter.encodedDuration(), waveform: waveform)
|
||||||
let sample: UInt16 = UInt16(Int64(scaledSamples[i]))
|
} else {
|
||||||
let minPeak = min(Int64(sample), Int64(calculatedPeak))
|
return nil
|
||||||
let resultPeak = minPeak * 31 / Int64(calculatedPeak)
|
|
||||||
scaledSamples[i] = Int16(clamping: min(31, resultPeak))
|
|
||||||
}
|
|
||||||
|
|
||||||
let resultWaveform = AudioWaveform(samples: Data(bytes: scaledSamplesMemory, count: 100 * 2), peak: 31)
|
|
||||||
let bitstream = resultWaveform.makeBitstream()
|
|
||||||
waveform = AudioWaveform(bitstream: bitstream, bitsPerSample: 5).makeBitstream()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return RecordedAudioData(compressedData: self.dataItem.data(), duration: self.oggWriter.encodedDuration(), waveform: waveform)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -361,12 +361,12 @@ final class PasscodeEntryControllerNode: ASDisplayNode {
|
|||||||
transition.updateFrame(node: self.keyboardNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
transition.updateFrame(node: self.keyboardNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||||
|
|
||||||
switch self.passcodeType {
|
switch self.passcodeType {
|
||||||
case .digits6, .digits4:
|
case .digits6, .digits4:
|
||||||
self.keyboardNode.alpha = 1.0
|
self.keyboardNode.alpha = 1.0
|
||||||
self.deleteButtonNode.alpha = 1.0
|
self.deleteButtonNode.alpha = 1.0
|
||||||
case .alphanumeric:
|
case .alphanumeric:
|
||||||
self.keyboardNode.alpha = 0.0
|
self.keyboardNode.alpha = 0.0
|
||||||
self.deleteButtonNode.alpha = 0.0
|
self.deleteButtonNode.alpha = 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
let bottomInset = layout.inputHeight ?? 0.0
|
let bottomInset = layout.inputHeight ?? 0.0
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
import AsyncDisplayKit
|
|
||||||
import Display
|
|
||||||
import Postbox
|
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
|||||||
case fontSize(PresentationTheme, PresentationFontSize)
|
case fontSize(PresentationTheme, PresentationFontSize)
|
||||||
case chatPreview(PresentationTheme, PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder)
|
case chatPreview(PresentationTheme, PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder)
|
||||||
case wallpaper(PresentationTheme, String)
|
case wallpaper(PresentationTheme, String)
|
||||||
case accentColor(PresentationTheme, String, PresentationThemeAccentColor?)
|
case accentColor(PresentationTheme, PresentationThemeReference, String, PresentationThemeAccentColor?)
|
||||||
case autoNightTheme(PresentationTheme, String, String)
|
case autoNightTheme(PresentationTheme, String, String)
|
||||||
case themeItem(PresentationTheme, PresentationStrings, [PresentationThemeReference], PresentationThemeReference, [Int64: PresentationThemeAccentColor], PresentationThemeAccentColor?)
|
case themeItem(PresentationTheme, PresentationStrings, [PresentationThemeReference], PresentationThemeReference, [Int64: PresentationThemeAccentColor], PresentationThemeAccentColor?)
|
||||||
case iconHeader(PresentationTheme, String)
|
case iconHeader(PresentationTheme, String)
|
||||||
@ -137,8 +137,8 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .accentColor(lhsTheme, lhsText, lhsColor):
|
case let .accentColor(lhsTheme, lhsCurrentTheme, lhsText, lhsColor):
|
||||||
if case let .accentColor(rhsTheme, rhsText, rhsColor) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsColor == rhsColor {
|
if case let .accentColor(rhsTheme, rhsCurrentTheme, rhsText, rhsColor) = rhs, lhsTheme === rhsTheme, lhsCurrentTheme == rhsCurrentTheme, lhsText == rhsText, lhsColor == rhsColor {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
@ -230,21 +230,20 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
|||||||
return ItemListDisclosureItem(theme: theme, title: text, label: "", sectionId: self.section, style: .blocks, action: {
|
return ItemListDisclosureItem(theme: theme, title: text, label: "", sectionId: self.section, style: .blocks, action: {
|
||||||
arguments.openWallpaperSettings()
|
arguments.openWallpaperSettings()
|
||||||
})
|
})
|
||||||
case let .accentColor(theme, _, color):
|
case let .accentColor(theme, currentTheme, _, color):
|
||||||
|
var defaultColor = PresentationThemeAccentColor(baseColor: .blue, value: 0.5)
|
||||||
var colors = PresentationThemeBaseColor.allCases
|
var colors = PresentationThemeBaseColor.allCases
|
||||||
if theme.overallDarkAppearance {
|
if case let .builtin(name) = currentTheme {
|
||||||
colors = colors.filter { $0 != .black }
|
if name == .night || name == .nightAccent {
|
||||||
|
colors = colors.filter { $0 != .black }
|
||||||
|
}
|
||||||
|
if name == .night {
|
||||||
|
colors = colors.filter { $0 != .gray }
|
||||||
|
defaultColor = PresentationThemeAccentColor(baseColor: .white, value: 0.5)
|
||||||
|
} else {
|
||||||
|
colors = colors.filter { $0 != .white }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let defaultColor: PresentationThemeAccentColor
|
|
||||||
if case let .builtin(name) = theme.name, name == .night {
|
|
||||||
colors = colors.filter { $0 != .gray }
|
|
||||||
defaultColor = PresentationThemeAccentColor(baseColor: .white, value: 0.5)
|
|
||||||
} else {
|
|
||||||
colors = colors.filter { $0 != .white }
|
|
||||||
defaultColor = PresentationThemeAccentColor(baseColor: .blue, value: 0.5)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ThemeSettingsAccentColorItem(theme: theme, sectionId: self.section, colors: colors, currentColor: color ?? defaultColor, updated: { color in
|
return ThemeSettingsAccentColorItem(theme: theme, sectionId: self.section, colors: colors, currentColor: color ?? defaultColor, updated: { color in
|
||||||
arguments.selectAccentColor(color)
|
arguments.selectAccentColor(color)
|
||||||
}, tag: ThemeSettingsEntryTag.accentColor)
|
}, tag: ThemeSettingsEntryTag.accentColor)
|
||||||
@ -297,7 +296,7 @@ private func themeSettingsControllerEntries(presentationData: PresentationData,
|
|||||||
entries.append(.themeItem(presentationData.theme, presentationData.strings, availableThemes, themeReference, themeSpecificAccentColors, themeSpecificAccentColors[themeReference.index]))
|
entries.append(.themeItem(presentationData.theme, presentationData.strings, availableThemes, themeReference, themeSpecificAccentColors, themeSpecificAccentColors[themeReference.index]))
|
||||||
|
|
||||||
if theme.name != .builtin(.dayClassic) {
|
if theme.name != .builtin(.dayClassic) {
|
||||||
entries.append(.accentColor(presentationData.theme, strings.Appearance_AccentColor, themeSpecificAccentColors[themeReference.index]))
|
entries.append(.accentColor(presentationData.theme, themeReference, strings.Appearance_AccentColor, themeSpecificAccentColors[themeReference.index]))
|
||||||
}
|
}
|
||||||
|
|
||||||
entries.append(.wallpaper(presentationData.theme, strings.Settings_ChatBackground))
|
entries.append(.wallpaper(presentationData.theme, strings.Settings_ChatBackground))
|
||||||
|
|||||||
@ -2070,7 +2070,6 @@
|
|||||||
D0F680091EE750EE000E5906 /* ChannelBannedMemberController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelBannedMemberController.swift; sourceTree = "<group>"; };
|
D0F680091EE750EE000E5906 /* ChannelBannedMemberController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChannelBannedMemberController.swift; sourceTree = "<group>"; };
|
||||||
D0F69CD61D6B87D30046BCD6 /* MediaManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaManager.swift; sourceTree = "<group>"; };
|
D0F69CD61D6B87D30046BCD6 /* MediaManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaManager.swift; sourceTree = "<group>"; };
|
||||||
D0F69DB91D6B88190046BCD6 /* TelegramUI.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = TelegramUI.xcconfig; path = TelegramUI/Config/TelegramUI.xcconfig; sourceTree = "<group>"; };
|
D0F69DB91D6B88190046BCD6 /* TelegramUI.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = TelegramUI.xcconfig; path = TelegramUI/Config/TelegramUI.xcconfig; sourceTree = "<group>"; };
|
||||||
D0F69DC21D6B89DA0046BCD6 /* TextNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextNode.swift; sourceTree = "<group>"; };
|
|
||||||
D0F69DC41D6B89E10046BCD6 /* RadialProgressNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadialProgressNode.swift; sourceTree = "<group>"; };
|
D0F69DC41D6B89E10046BCD6 /* RadialProgressNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadialProgressNode.swift; sourceTree = "<group>"; };
|
||||||
D0F69DCD1D6B8A0D0046BCD6 /* SearchDisplayController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchDisplayController.swift; sourceTree = "<group>"; };
|
D0F69DCD1D6B8A0D0046BCD6 /* SearchDisplayController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchDisplayController.swift; sourceTree = "<group>"; };
|
||||||
D0F69DCE1D6B8A0D0046BCD6 /* SearchDisplayControllerContentNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchDisplayControllerContentNode.swift; sourceTree = "<group>"; };
|
D0F69DCE1D6B8A0D0046BCD6 /* SearchDisplayControllerContentNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchDisplayControllerContentNode.swift; sourceTree = "<group>"; };
|
||||||
@ -3993,7 +3992,6 @@
|
|||||||
D0477D191F617E4B00412B44 /* Video */,
|
D0477D191F617E4B00412B44 /* Video */,
|
||||||
D0F69DC41D6B89E10046BCD6 /* RadialProgressNode.swift */,
|
D0F69DC41D6B89E10046BCD6 /* RadialProgressNode.swift */,
|
||||||
D00C7CE51E378FD00080C3D5 /* RadialTimeoutNode.swift */,
|
D00C7CE51E378FD00080C3D5 /* RadialTimeoutNode.swift */,
|
||||||
D0F69DC21D6B89DA0046BCD6 /* TextNode.swift */,
|
|
||||||
D0943AF51FDAAE7E001522CC /* MultipleAvatarsNode.swift */,
|
D0943AF51FDAAE7E001522CC /* MultipleAvatarsNode.swift */,
|
||||||
D0568AAC1DF198130022E7DA /* AudioWaveformNode.swift */,
|
D0568AAC1DF198130022E7DA /* AudioWaveformNode.swift */,
|
||||||
D0BC38621E3F9EFA0044D6FE /* EditableTokenListNode.swift */,
|
D0BC38621E3F9EFA0044D6FE /* EditableTokenListNode.swift */,
|
||||||
@ -4942,7 +4940,6 @@
|
|||||||
D008177D22B46B7E008A895F /* TGContactModel.m in Sources */,
|
D008177D22B46B7E008A895F /* TGContactModel.m in Sources */,
|
||||||
D0EC6D301EB9F58800EBF1C3 /* RadialProgressNode.swift in Sources */,
|
D0EC6D301EB9F58800EBF1C3 /* RadialProgressNode.swift in Sources */,
|
||||||
D0EC6D311EB9F58800EBF1C3 /* RadialTimeoutNode.swift in Sources */,
|
D0EC6D311EB9F58800EBF1C3 /* RadialTimeoutNode.swift in Sources */,
|
||||||
D0EC6D321EB9F58800EBF1C3 /* TextNode.swift in Sources */,
|
|
||||||
D0BFAE5020AB2A1300793CF2 /* PeerBanTimeoutController.swift in Sources */,
|
D0BFAE5020AB2A1300793CF2 /* PeerBanTimeoutController.swift in Sources */,
|
||||||
09CE950A2237B93500A7D2C3 /* SettingsSearchResultItem.swift in Sources */,
|
09CE950A2237B93500A7D2C3 /* SettingsSearchResultItem.swift in Sources */,
|
||||||
D0AE303922B1D3620058D3BC /* LegacyBridgeAudio.swift in Sources */,
|
D0AE303922B1D3620058D3BC /* LegacyBridgeAudio.swift in Sources */,
|
||||||
|
|||||||
@ -426,39 +426,24 @@ static inline int writeOggPage(ogg_page *page, TGDataItem *fileItem)
|
|||||||
pages_out++;
|
pages_out++;
|
||||||
}
|
}
|
||||||
|
|
||||||
op.packet = (unsigned char *)_packet;
|
if (framePcmBytes != NULL) {
|
||||||
op.bytes = nbBytes;
|
op.packet = (unsigned char *)_packet;
|
||||||
op.b_o_s = 0;
|
op.bytes = nbBytes;
|
||||||
op.granulepos = enc_granulepos;
|
op.b_o_s = 0;
|
||||||
if (op.e_o_s)
|
op.granulepos = enc_granulepos;
|
||||||
{
|
|
||||||
/* We compute the final GP as ceil(len*48k/input_rate). When a resampling
|
|
||||||
decoder does the matching floor(len*input/48k) conversion the length will
|
|
||||||
be exactly the same as the input.
|
|
||||||
*/
|
|
||||||
op.granulepos = ((total_samples * 48000 + rate - 1) / rate) + header.preskip;
|
|
||||||
}
|
|
||||||
op.packetno = 2 + _packetId;
|
|
||||||
ogg_stream_packetin(&os, &op);
|
|
||||||
last_segments += size_segments;
|
|
||||||
|
|
||||||
/* The downside of early reading is if the input is an exact
|
if (op.e_o_s)
|
||||||
multiple of the frame_size you'll get an extra frame that needs
|
{
|
||||||
to get cropped off. The downside of late reading is added delay.
|
/* We compute the final GP as ceil(len*48k/input_rate). When a resampling
|
||||||
If your ogg_delay is 120ms or less we'll assume you want the
|
decoder does the matching floor(len*input/48k) conversion the length will
|
||||||
low delay behavior.
|
be exactly the same as the input.
|
||||||
*/
|
*/
|
||||||
/*if ((!op.e_o_s) && max_ogg_delay > 5760)
|
op.granulepos = ((total_samples * 48000 + rate - 1) / rate) + header.preskip;
|
||||||
{
|
}
|
||||||
nb_samples = inopt.read_samples(inopt.readdata, input, frame_size);
|
op.packetno = 2 + _packetId;
|
||||||
total_samples += nb_samples;
|
ogg_stream_packetin(&os, &op);
|
||||||
if (nb_samples < frame_size)
|
last_segments += size_segments;
|
||||||
eos = 1;
|
|
||||||
if (nb_samples == 0)
|
|
||||||
op.e_o_s = 1;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
nb_samples = -1;*/
|
|
||||||
|
|
||||||
// If the stream is over or we're sure that the delayed flush will fire, go ahead and flush now to avoid adding delay
|
// If the stream is over or we're sure that the delayed flush will fire, go ahead and flush now to avoid adding delay
|
||||||
while ((op.e_o_s || (enc_granulepos + (frame_size * 48000 / coding_rate) - last_granulepos > max_ogg_delay) ||
|
while ((op.e_o_s || (enc_granulepos + (frame_size * 48000 / coding_rate) - last_granulepos > max_ogg_delay) ||
|
||||||
|
|||||||
@ -35,6 +35,7 @@
|
|||||||
D0C9C3D52300BA8B00FAB518 /* FrameworkBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C9C3D42300BA8B00FAB518 /* FrameworkBundle.swift */; };
|
D0C9C3D52300BA8B00FAB518 /* FrameworkBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C9C3D42300BA8B00FAB518 /* FrameworkBundle.swift */; };
|
||||||
D0C9C4442300DC2000FAB518 /* ChatBubbleVideoDecoration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C9C4422300DC2000FAB518 /* ChatBubbleVideoDecoration.swift */; };
|
D0C9C4442300DC2000FAB518 /* ChatBubbleVideoDecoration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C9C4422300DC2000FAB518 /* ChatBubbleVideoDecoration.swift */; };
|
||||||
D0C9C4452300DC2000FAB518 /* ChatBubbleInstantVideoDecoration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C9C4432300DC2000FAB518 /* ChatBubbleInstantVideoDecoration.swift */; };
|
D0C9C4452300DC2000FAB518 /* ChatBubbleInstantVideoDecoration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C9C4432300DC2000FAB518 /* ChatBubbleInstantVideoDecoration.swift */; };
|
||||||
|
D0C9C5362301CCC600FAB518 /* PhotoResources.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C9C5352301CCC600FAB518 /* PhotoResources.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
@ -69,6 +70,7 @@
|
|||||||
D0C9C3D42300BA8B00FAB518 /* FrameworkBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrameworkBundle.swift; sourceTree = "<group>"; };
|
D0C9C3D42300BA8B00FAB518 /* FrameworkBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrameworkBundle.swift; sourceTree = "<group>"; };
|
||||||
D0C9C4422300DC2000FAB518 /* ChatBubbleVideoDecoration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatBubbleVideoDecoration.swift; sourceTree = "<group>"; };
|
D0C9C4422300DC2000FAB518 /* ChatBubbleVideoDecoration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatBubbleVideoDecoration.swift; sourceTree = "<group>"; };
|
||||||
D0C9C4432300DC2000FAB518 /* ChatBubbleInstantVideoDecoration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatBubbleInstantVideoDecoration.swift; sourceTree = "<group>"; };
|
D0C9C4432300DC2000FAB518 /* ChatBubbleInstantVideoDecoration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatBubbleInstantVideoDecoration.swift; sourceTree = "<group>"; };
|
||||||
|
D0C9C5352301CCC600FAB518 /* PhotoResources.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = PhotoResources.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -76,6 +78,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
D0C9C5362301CCC600FAB518 /* PhotoResources.framework in Frameworks */,
|
||||||
D0C9C3D12300BA4F00FAB518 /* RadialStatusNode.framework in Frameworks */,
|
D0C9C3D12300BA4F00FAB518 /* RadialStatusNode.framework in Frameworks */,
|
||||||
D0C9C3CF2300BA4400FAB518 /* TelegramAudio.framework in Frameworks */,
|
D0C9C3CF2300BA4400FAB518 /* TelegramAudio.framework in Frameworks */,
|
||||||
D0C9C3CB2300BA3300FAB518 /* LegacyComponents.framework in Frameworks */,
|
D0C9C3CB2300BA3300FAB518 /* LegacyComponents.framework in Frameworks */,
|
||||||
@ -138,6 +141,7 @@
|
|||||||
D0C9C3882300B41900FAB518 /* Frameworks */ = {
|
D0C9C3882300B41900FAB518 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D0C9C5352301CCC600FAB518 /* PhotoResources.framework */,
|
||||||
D0C9C3D02300BA4F00FAB518 /* RadialStatusNode.framework */,
|
D0C9C3D02300BA4F00FAB518 /* RadialStatusNode.framework */,
|
||||||
D0C9C3CE2300BA4400FAB518 /* TelegramAudio.framework */,
|
D0C9C3CE2300BA4400FAB518 /* TelegramAudio.framework */,
|
||||||
D0C9C3CC2300BA3800FAB518 /* TelegramUI.framework */,
|
D0C9C3CC2300BA3800FAB518 /* TelegramUI.framework */,
|
||||||
|
|||||||
@ -32,7 +32,8 @@ public extension CharacterSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func isValidUrl(_ url: String) -> Bool {
|
public func isValidUrl(_ url: String) -> Bool {
|
||||||
if let url = URL(string: url), ["http", "https"].contains(url.scheme), let host = url.host, host.contains(".") && url.user == nil {
|
|
||||||
|
if let escapedUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: escapedUrl), ["http", "https"].contains(url.scheme), let host = url.host, host.contains(".") && url.user == nil {
|
||||||
let components = host.components(separatedBy: ".")
|
let components = host.components(separatedBy: ".")
|
||||||
let domain = (components.first ?? "")
|
let domain = (components.first ?? "")
|
||||||
if domain.isEmpty {
|
if domain.isEmpty {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user