Merge commit '083e9236109a5a61dfef75070d204ff9e1a9c9f8'

This commit is contained in:
Peter 2019-08-12 19:39:06 +03:00
commit c0789dffda
23 changed files with 407 additions and 376 deletions

View File

@ -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())")
} }

View File

@ -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

View File

@ -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>

View File

@ -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 {

View File

@ -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 {

View File

@ -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 */,

View File

@ -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:@"="];
} }

View File

@ -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 {

View File

@ -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 */,

View File

@ -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
} }

View File

@ -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()

View File

@ -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

View File

@ -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;
} }

View File

@ -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)

View File

@ -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

View File

@ -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)
} }
} }

View File

@ -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

View File

@ -1,6 +0,0 @@
import Foundation
import UIKit
import AsyncDisplayKit
import Display
import Postbox

View File

@ -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))

View File

@ -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 */,

View File

@ -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) ||

View File

@ -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 */,

View File

@ -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 {