[WIP] General UI improvements

This commit is contained in:
Ali 2022-09-16 22:59:16 +04:00
parent f05031cc9d
commit ff22c7e981
34 changed files with 497 additions and 171 deletions

View File

@ -464,7 +464,7 @@ private struct NotificationContent: CustomStringConvertible {
return string
}
mutating func addSenderInfo(mediaBox: MediaBox, accountPeerId: PeerId, peer: Peer) {
mutating func addSenderInfo(mediaBox: MediaBox, accountPeerId: PeerId, peer: Peer, contactIdentifier: String?) {
if #available(iOS 15.0, *) {
let image = peerAvatar(mediaBox: mediaBox, accountPeerId: accountPeerId, peer: peer)
@ -483,7 +483,7 @@ private struct NotificationContent: CustomStringConvertible {
nameComponents: personNameComponents,
displayName: displayName,
image: image,
contactIdentifier: nil,
contactIdentifier: contactIdentifier,
customIdentifier: "\(peer.id.toInt64())",
isMe: false,
suggestionType: .none
@ -818,6 +818,7 @@ private final class NotificationServiceHandler {
var updates: String
var accountId: Int64
var peer: EnginePeer?
var localContactId: String?
}
var callData: CallData?
@ -1033,35 +1034,51 @@ private final class NotificationServiceHandler {
if let action = action {
switch action {
case let .call(callData):
let voipPayload: [AnyHashable: Any] = [
"call_id": "\(callData.id)",
"call_ah": "\(callData.accessHash)",
"from_id": "\(callData.fromId.id._internalGetInt64Value())",
"updates": callData.updates,
"accountId": "\(callData.accountId)"
]
if #available(iOS 14.5, *), voiceCallSettings.enableSystemIntegration {
Logger.shared.log("NotificationService \(episode)", "Will report voip notification")
if let stateManager = strongSelf.stateManager {
let content = NotificationContent(isLockedMessage: nil)
updateCurrentContent(content)
CXProvider.reportNewIncomingVoIPPushPayload(voipPayload, completion: { error in
Logger.shared.log("NotificationService \(episode)", "Did report voip notification, error: \(String(describing: error))")
let _ = (stateManager.postbox.transaction { transaction -> String? in
if let peer = transaction.getPeer(callData.fromId) as? TelegramUser {
return peer.phone
} else {
return nil
}
}).start(next: { phoneNumber in
var voipPayload: [AnyHashable: Any] = [
"call_id": "\(callData.id)",
"call_ah": "\(callData.accessHash)",
"from_id": "\(callData.fromId.id._internalGetInt64Value())",
"updates": callData.updates,
"accountId": "\(callData.accountId)"
]
if let phoneNumber = phoneNumber {
voipPayload["phoneNumber"] = phoneNumber
}
completed()
if #available(iOS 14.5, *), voiceCallSettings.enableSystemIntegration {
Logger.shared.log("NotificationService \(episode)", "Will report voip notification")
let content = NotificationContent(isLockedMessage: nil)
updateCurrentContent(content)
CXProvider.reportNewIncomingVoIPPushPayload(voipPayload, completion: { error in
Logger.shared.log("NotificationService \(episode)", "Did report voip notification, error: \(String(describing: error))")
completed()
})
} else {
var content = NotificationContent(isLockedMessage: nil)
if let peer = callData.peer {
content.title = peer.debugDisplayTitle
content.body = incomingCallMessage
} else {
content.body = "Incoming Call"
}
updateCurrentContent(content)
completed()
}
})
} else {
var content = NotificationContent(isLockedMessage: nil)
if let peer = callData.peer {
content.title = peer.debugDisplayTitle
content.body = incomingCallMessage
} else {
content.body = "Incoming Call"
}
updateCurrentContent(content)
completed()
}
case .logout:
Logger.shared.log("NotificationService \(episode)", "Will logout")
@ -1334,7 +1351,23 @@ private final class NotificationServiceHandler {
if let interactionAuthorId = interactionAuthorId {
if inAppNotificationSettings.displayNameOnLockscreen, let peer = transaction.getPeer(interactionAuthorId) {
content.addSenderInfo(mediaBox: stateManager.postbox.mediaBox, accountPeerId: stateManager.accountPeerId, peer: peer)
var foundLocalId: String?
transaction.enumerateDeviceContactImportInfoItems({ _, value in
if let value = value as? TelegramDeviceContactImportedData {
switch value {
case let .imported(data, _, peerId):
if peerId == interactionAuthorId {
foundLocalId = data.localIdentifiers.first
return false
}
default:
break
}
}
return true
})
content.addSenderInfo(mediaBox: stateManager.postbox.mediaBox, accountPeerId: stateManager.accountPeerId, peer: peer, contactIdentifier: foundLocalId)
}
}

View File

@ -482,7 +482,7 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
for node in nodes {
other.addSubnode(node)
node.layer.animateAlpha(from: node.alpha, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak node] _ in
node.layer.animateAlpha(from: node.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak node] _ in
node?.removeFromSupernode()
})
}
@ -491,12 +491,11 @@ final class InnerTextSelectionTipContainerNode: ASDisplayNode {
func animateContentIn() {
let nodes: [ASDisplayNode] = [
self.textNode.textNode,
self.iconNode,
self.placeholderNode
self.iconNode
]
for node in nodes {
node.layer.animateAlpha(from: 0.0, to: node.alpha, duration: 0.2)
node.layer.animateAlpha(from: 0.0, to: node.alpha, duration: 0.25)
}
}

View File

@ -378,6 +378,7 @@ open class NavigationController: UINavigationController, ContainableController,
let belowKeyboardOverlayLayout = layout
var globalOverlayLayout = layout
globalOverlayLayout.inputHeight = nil
if let globalOverlayBelowKeyboardContainerParent = self.globalOverlayBelowKeyboardContainerParent {
if globalOverlayBelowKeyboardContainerParent.view.superview != self.displayNode.view {

View File

@ -53,6 +53,9 @@ private func transcribeAudio(path: String, locale: String) -> Signal<Transcripti
let _ = try? FileManager.default.copyItem(atPath: path, toPath: tempFilePath)
let request = SFSpeechURLRecognitionRequest(url: URL(fileURLWithPath: tempFilePath))
if #available(iOS 16.0, *) {
request.addsPunctuation = true
}
request.requiresOnDeviceRecognition = speechRecognizer.supportsOnDeviceRecognition
request.shouldReportPartialResults = true

View File

@ -1334,9 +1334,11 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
for attribute in item.file.attributes {
switch attribute {
case let .CustomEmoji(_, alt, _):
if !alt.isEmpty, let keyword = allEmoticons[alt] {
if !item.file.isPremiumEmoji || hasPremium {
if !item.file.isPremiumEmoji || hasPremium {
if !alt.isEmpty, let keyword = allEmoticons[alt] {
result.append((alt, item.file, keyword))
} else if alt == query {
result.append((alt, item.file, alt))
}
}
default:
@ -1345,12 +1347,6 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
}
}
for keyword in keywords {
for emoticon in keyword.emoticons {
result.append((emoticon, nil, keyword.keyword))
}
}
var items: [EmojiPagerContentComponent.Item] = []
var existingIds = Set<MediaId>()

View File

@ -730,10 +730,11 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1660637285] = { return Api.StatsGroupTopPoster.parse_statsGroupTopPoster($0) }
dict[-875679776] = { return Api.StatsPercentValue.parse_statsPercentValue($0) }
dict[1202287072] = { return Api.StatsURL.parse_statsURL($0) }
dict[-50416996] = { return Api.StickerKeyword.parse_stickerKeyword($0) }
dict[313694676] = { return Api.StickerPack.parse_stickerPack($0) }
dict[768691932] = { return Api.StickerSet.parse_stickerSet($0) }
dict[1678812626] = { return Api.StickerSetCovered.parse_stickerSetCovered($0) }
dict[451763941] = { return Api.StickerSetCovered.parse_stickerSetFullCovered($0) }
dict[1087454222] = { return Api.StickerSetCovered.parse_stickerSetFullCovered($0) }
dict[872932635] = { return Api.StickerSetCovered.parse_stickerSetMultiCovered($0) }
dict[-1609668650] = { return Api.Theme.parse_theme($0) }
dict[-94849324] = { return Api.ThemeSettings.parse_themeSettings($0) }
@ -1029,7 +1030,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1802240206] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedFile($0) }
dict[1443858741] = { return Api.messages.SentEncryptedMessage.parse_sentEncryptedMessage($0) }
dict[1705297877] = { return Api.messages.SponsoredMessages.parse_sponsoredMessages($0) }
dict[-1240849242] = { return Api.messages.StickerSet.parse_stickerSet($0) }
dict[1846886166] = { return Api.messages.StickerSet.parse_stickerSet($0) }
dict[-738646805] = { return Api.messages.StickerSet.parse_stickerSetNotModified($0) }
dict[904138920] = { return Api.messages.StickerSetInstallResult.parse_stickerSetInstallResultArchive($0) }
dict[946083368] = { return Api.messages.StickerSetInstallResult.parse_stickerSetInstallResultSuccess($0) }
@ -1584,6 +1585,8 @@ public extension Api {
_1.serialize(buffer, boxed)
case let _1 as Api.StatsURL:
_1.serialize(buffer, boxed)
case let _1 as Api.StickerKeyword:
_1.serialize(buffer, boxed)
case let _1 as Api.StickerPack:
_1.serialize(buffer, boxed)
case let _1 as Api.StickerSet:

View File

@ -1,3 +1,49 @@
public extension Api {
enum StickerKeyword: TypeConstructorDescription {
case stickerKeyword(documentId: Int64, keyword: [String])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .stickerKeyword(let documentId, let keyword):
if boxed {
buffer.appendInt32(-50416996)
}
serializeInt64(documentId, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(keyword.count))
for item in keyword {
serializeString(item, buffer: buffer, boxed: false)
}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .stickerKeyword(let documentId, let keyword):
return ("stickerKeyword", [("documentId", String(describing: documentId)), ("keyword", String(describing: keyword))])
}
}
public static func parse_stickerKeyword(_ reader: BufferReader) -> StickerKeyword? {
var _1: Int64?
_1 = reader.readInt64()
var _2: [String]?
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: -1255641564, elementType: String.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.StickerKeyword.stickerKeyword(documentId: _1!, keyword: _2!)
}
else {
return nil
}
}
}
}
public extension Api {
enum StickerPack: TypeConstructorDescription {
case stickerPack(emoticon: String, documents: [Int64])
@ -133,7 +179,7 @@ public extension Api {
public extension Api {
enum StickerSetCovered: TypeConstructorDescription {
case stickerSetCovered(set: Api.StickerSet, cover: Api.Document)
case stickerSetFullCovered(set: Api.StickerSet, packs: [Api.StickerPack], documents: [Api.Document])
case stickerSetFullCovered(set: Api.StickerSet, packs: [Api.StickerPack], keywords: [Api.StickerKeyword], documents: [Api.Document])
case stickerSetMultiCovered(set: Api.StickerSet, covers: [Api.Document])
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
@ -145,9 +191,9 @@ public extension Api {
set.serialize(buffer, true)
cover.serialize(buffer, true)
break
case .stickerSetFullCovered(let set, let packs, let documents):
case .stickerSetFullCovered(let set, let packs, let keywords, let documents):
if boxed {
buffer.appendInt32(451763941)
buffer.appendInt32(1087454222)
}
set.serialize(buffer, true)
buffer.appendInt32(481674261)
@ -156,6 +202,11 @@ public extension Api {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(keywords.count))
for item in keywords {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(documents.count))
for item in documents {
item.serialize(buffer, true)
@ -179,8 +230,8 @@ public extension Api {
switch self {
case .stickerSetCovered(let set, let cover):
return ("stickerSetCovered", [("set", String(describing: set)), ("cover", String(describing: cover))])
case .stickerSetFullCovered(let set, let packs, let documents):
return ("stickerSetFullCovered", [("set", String(describing: set)), ("packs", String(describing: packs)), ("documents", String(describing: documents))])
case .stickerSetFullCovered(let set, let packs, let keywords, let documents):
return ("stickerSetFullCovered", [("set", String(describing: set)), ("packs", String(describing: packs)), ("keywords", String(describing: keywords)), ("documents", String(describing: documents))])
case .stickerSetMultiCovered(let set, let covers):
return ("stickerSetMultiCovered", [("set", String(describing: set)), ("covers", String(describing: covers))])
}
@ -213,15 +264,20 @@ public extension Api {
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerPack.self)
}
var _3: [Api.Document]?
var _3: [Api.StickerKeyword]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self)
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerKeyword.self)
}
var _4: [Api.Document]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.StickerSetCovered.stickerSetFullCovered(set: _1!, packs: _2!, documents: _3!)
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.StickerSetCovered.stickerSetFullCovered(set: _1!, packs: _2!, keywords: _3!, documents: _4!)
}
else {
return nil

View File

@ -638,14 +638,14 @@ public extension Api.messages {
}
public extension Api.messages {
enum StickerSet: TypeConstructorDescription {
case stickerSet(set: Api.StickerSet, packs: [Api.StickerPack], documents: [Api.Document])
case stickerSet(set: Api.StickerSet, packs: [Api.StickerPack], keywords: [Api.StickerKeyword], documents: [Api.Document])
case stickerSetNotModified
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .stickerSet(let set, let packs, let documents):
case .stickerSet(let set, let packs, let keywords, let documents):
if boxed {
buffer.appendInt32(-1240849242)
buffer.appendInt32(1846886166)
}
set.serialize(buffer, true)
buffer.appendInt32(481674261)
@ -654,6 +654,11 @@ public extension Api.messages {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(keywords.count))
for item in keywords {
item.serialize(buffer, true)
}
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(documents.count))
for item in documents {
item.serialize(buffer, true)
@ -670,8 +675,8 @@ public extension Api.messages {
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .stickerSet(let set, let packs, let documents):
return ("stickerSet", [("set", String(describing: set)), ("packs", String(describing: packs)), ("documents", String(describing: documents))])
case .stickerSet(let set, let packs, let keywords, let documents):
return ("stickerSet", [("set", String(describing: set)), ("packs", String(describing: packs)), ("keywords", String(describing: keywords)), ("documents", String(describing: documents))])
case .stickerSetNotModified:
return ("stickerSetNotModified", [])
}
@ -686,15 +691,20 @@ public extension Api.messages {
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerPack.self)
}
var _3: [Api.Document]?
var _3: [Api.StickerKeyword]?
if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self)
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StickerKeyword.self)
}
var _4: [Api.Document]?
if let _ = reader.readInt32() {
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self)
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.messages.StickerSet.stickerSet(set: _1!, packs: _2!, documents: _3!)
let _c4 = _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.messages.StickerSet.stickerSet(set: _1!, packs: _2!, keywords: _3!, documents: _4!)
}
else {
return nil

View File

@ -104,6 +104,7 @@ swift_library(
"//submodules/Components/UndoPanelComponent:UndoPanelComponent",
"//submodules/Components/HierarchyTrackingLayer:HierarchyTrackingLayer",
"//submodules/PeerInfoUI/CreateExternalMediaStreamScreen:CreateExternalMediaStreamScreen",
"//submodules/PhoneNumberFormat:PhoneNumberFormat",
],
visibility = [
"//visibility:public",

View File

@ -41,7 +41,7 @@ public final class CallKitIntegration {
}
func setup(
startCall: @escaping (AccountContext, UUID, String, Bool) -> Signal<Bool, NoError>,
startCall: @escaping (AccountContext, UUID, EnginePeer.Id?, String, Bool) -> Signal<Bool, NoError>,
answerCall: @escaping (UUID) -> Void,
endCall: @escaping (UUID) -> Signal<Bool, NoError>,
setCallMuted: @escaping (UUID, Bool) -> Void,
@ -56,22 +56,17 @@ public final class CallKitIntegration {
if !CallKitIntegration.isAvailable {
return nil
}
#if targetEnvironment(simulator)
return nil
#else
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
} else {
return nil
}
#endif
}
func startCall(context: AccountContext, peerId: PeerId, isVideo: Bool, displayTitle: String) {
func startCall(context: AccountContext, peerId: PeerId, phoneNumber: String?, localContactId: String?, isVideo: Bool, displayTitle: String) {
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
(sharedProviderDelegate as? CallKitProviderDelegate)?.startCall(context: context, peerId: peerId, isVideo: isVideo, displayTitle: displayTitle)
self.donateIntent(peerId: peerId, displayTitle: displayTitle)
(sharedProviderDelegate as? CallKitProviderDelegate)?.startCall(context: context, peerId: peerId, phoneNumber: phoneNumber, isVideo: isVideo, displayTitle: displayTitle)
self.donateIntent(peerId: peerId, displayTitle: displayTitle, localContactId: localContactId)
}
}
@ -87,9 +82,9 @@ public final class CallKitIntegration {
}
}
public func reportIncomingCall(uuid: UUID, stableId: Int64, handle: String, isVideo: Bool, displayTitle: String, completion: ((NSError?) -> Void)?) {
public func reportIncomingCall(uuid: UUID, stableId: Int64, handle: String, phoneNumber: String?, isVideo: Bool, displayTitle: String, completion: ((NSError?) -> Void)?) {
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
(sharedProviderDelegate as? CallKitProviderDelegate)?.reportIncomingCall(uuid: uuid, stableId: stableId, handle: handle, isVideo: isVideo, displayTitle: displayTitle, completion: completion)
(sharedProviderDelegate as? CallKitProviderDelegate)?.reportIncomingCall(uuid: uuid, stableId: stableId, handle: handle, phoneNumber: phoneNumber, isVideo: isVideo, displayTitle: displayTitle, completion: completion)
}
}
@ -99,10 +94,10 @@ public final class CallKitIntegration {
}
}
private func donateIntent(peerId: PeerId, displayTitle: String) {
private func donateIntent(peerId: PeerId, displayTitle: String, localContactId: String?) {
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
let handle = INPersonHandle(value: "tg\(peerId.id)", type: .unknown)
let contact = INPerson(personHandle: handle, nameComponents: nil, displayName: displayTitle, image: nil, contactIdentifier: nil, customIdentifier: "tg\(peerId.id)")
let handle = INPersonHandle(value: "tg\(peerId.id._internalGetInt64Value())", type: .unknown)
let contact = INPerson(personHandle: handle, nameComponents: nil, displayName: displayTitle, image: nil, contactIdentifier: localContactId, customIdentifier: "tg\(peerId.id._internalGetInt64Value())")
let intent = INStartAudioCallIntent(contacts: [contact])
@ -122,8 +117,9 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
private var currentStartCallAccount: (UUID, AccountContext)?
private var alreadyReportedIncomingCalls = Set<UUID>()
private var uuidToPeerIdMapping: [UUID: EnginePeer.Id] = [:]
private var startCall: ((AccountContext, UUID, String, Bool) -> Signal<Bool, NoError>)?
private var startCall: ((AccountContext, UUID, EnginePeer.Id?, String, Bool) -> Signal<Bool, NoError>)?
private var answerCall: ((UUID) -> Void)?
private var endCall: ((UUID) -> Signal<Bool, NoError>)?
private var setCallMuted: ((UUID, Bool) -> Void)?
@ -141,7 +137,7 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
self.provider.setDelegate(self, queue: nil)
}
func setup(audioSessionActivePromise: ValuePromise<Bool>, startCall: @escaping (AccountContext, UUID, String, Bool) -> Signal<Bool, NoError>, answerCall: @escaping (UUID) -> Void, endCall: @escaping (UUID) -> Signal<Bool, NoError>, setCallMuted: @escaping (UUID, Bool) -> Void, audioSessionActivationChanged: @escaping (Bool) -> Void) {
func setup(audioSessionActivePromise: ValuePromise<Bool>, startCall: @escaping (AccountContext, UUID, EnginePeer.Id?, String, Bool) -> Signal<Bool, NoError>, answerCall: @escaping (UUID) -> Void, endCall: @escaping (UUID) -> Signal<Bool, NoError>, setCallMuted: @escaping (UUID, Bool) -> Void, audioSessionActivationChanged: @escaping (Bool) -> Void) {
self.audioSessionActivePromise = audioSessionActivePromise
self.startCall = startCall
self.answerCall = answerCall
@ -189,10 +185,18 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
self.requestTransaction(transaction)
}
func startCall(context: AccountContext, peerId: PeerId, isVideo: Bool, displayTitle: String) {
func startCall(context: AccountContext, peerId: PeerId, phoneNumber: String?, isVideo: Bool, displayTitle: String) {
let uuid = UUID()
self.currentStartCallAccount = (uuid, context)
let handle = CXHandle(type: .generic, value: "\(peerId.id._internalGetInt64Value())")
let handle: CXHandle
if let phoneNumber = phoneNumber {
handle = CXHandle(type: .phoneNumber, value: phoneNumber)
} else {
handle = CXHandle(type: .generic, value: "\(peerId.id._internalGetInt64Value())")
}
self.uuidToPeerIdMapping[uuid] = peerId
let startCallAction = CXStartCallAction(call: uuid, handle: handle)
startCallAction.contactIdentifier = displayTitle
@ -212,7 +216,7 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
})
}
func reportIncomingCall(uuid: UUID, stableId: Int64, handle: String, isVideo: Bool, displayTitle: String, completion: ((NSError?) -> Void)?) {
func reportIncomingCall(uuid: UUID, stableId: Int64, handle: String, phoneNumber: String?, isVideo: Bool, displayTitle: String, completion: ((NSError?) -> Void)?) {
if self.alreadyReportedIncomingCalls.contains(uuid) {
completion?(nil)
return
@ -220,7 +224,13 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
self.alreadyReportedIncomingCalls.insert(uuid)
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .generic, value: handle)
let nativeHandle: CXHandle
if let phoneNumber = phoneNumber {
nativeHandle = CXHandle(type: .phoneNumber, value: phoneNumber)
} else {
nativeHandle = CXHandle(type: .generic, value: handle)
}
update.remoteHandle = nativeHandle
update.localizedCallerName = displayTitle
update.supportsHolding = false
update.supportsGrouping = false
@ -252,7 +262,10 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
self.currentStartCallAccount = nil
let disposable = MetaDisposable()
self.disposableSet.add(disposable)
disposable.set((startCall(context, action.callUUID, action.handle.value, action.isVideo)
let peerId = self.uuidToPeerIdMapping[action.callUUID]
disposable.set((startCall(context, action.callUUID, peerId, action.handle.value, action.isVideo)
|> deliverOnMainQueue
|> afterDisposed { [weak self, weak disposable] in
if let strongSelf = self, let disposable = disposable {

View File

@ -13,6 +13,7 @@ import DeviceAccess
import UniversalMediaPlayer
import AccountContext
import DeviceProximity
import PhoneNumberFormat
final class PresentationCallToneRenderer {
let queue: Queue
@ -607,10 +608,15 @@ public final class PresentationCallImpl: PresentationCall {
if previous == nil || previousControl == nil {
if !self.reportedIncomingCall, let stableId = sessionState.stableId {
self.reportedIncomingCall = true
var phoneNumber: String?
if let peer = self.peer as? TelegramUser, let phone = peer.phone {
phoneNumber = formatPhoneNumber(phone)
}
self.callKitIntegration?.reportIncomingCall(
uuid: self.internalId,
stableId: stableId,
handle: "\(self.peerId.id._internalGetInt64Value())",
phoneNumber: phoneNumber,
isVideo: sessionState.type == .video,
displayTitle: self.peer?.debugDisplayTitle ?? "Unknown",
completion: { [weak self] error in

View File

@ -11,6 +11,7 @@ import TelegramVoip
import TelegramUIPreferences
import AccountContext
import CallKit
import PhoneNumberFormat
private func callKitIntegrationIfEnabled(_ integration: CallKitIntegration?, settings: VoiceCallSettings?) -> CallKitIntegration? {
let enabled = settings?.enableSystemIntegration ?? true
@ -128,16 +129,16 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
self.isMediaPlaying = isMediaPlaying
self.resumeMediaPlayback = resumeMediaPlayback
var startCallImpl: ((AccountContext, UUID, String, Bool) -> Signal<Bool, NoError>)?
var startCallImpl: ((AccountContext, UUID, EnginePeer.Id?, String, Bool) -> Signal<Bool, NoError>)?
var answerCallImpl: ((UUID) -> Void)?
var endCallImpl: ((UUID) -> Signal<Bool, NoError>)?
var setCallMutedImpl: ((UUID, Bool) -> Void)?
var audioSessionActivationChangedImpl: ((Bool) -> Void)?
self.callKitIntegration = CallKitIntegration.shared
self.callKitIntegration?.setup(startCall: { context, uuid, handle, isVideo in
self.callKitIntegration?.setup(startCall: { context, uuid, maybePeerId, handle, isVideo in
if let startCallImpl = startCallImpl {
return startCallImpl(context, uuid, handle, isVideo)
return startCallImpl(context, uuid, maybePeerId, handle, isVideo)
} else {
return .single(false)
}
@ -215,16 +216,26 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
self?.ringingStatesUpdated(ringingStates, enableCallKit: enableCallKit)
})
startCallImpl = { [weak self] context, uuid, handle, isVideo in
if let strongSelf = self, let userId = Int64(handle) {
return strongSelf.startCall(context: context, peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), isVideo: isVideo, internalId: uuid)
|> take(1)
|> map { result -> Bool in
return result
}
} else {
startCallImpl = { [weak self] context, uuid, maybePeerId, handle, isVideo in
guard let strongSelf = self else {
return .single(false)
}
var peerId: PeerId?
if let maybePeerId = maybePeerId {
peerId = maybePeerId
} else if let userId = Int64(handle) {
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
}
guard let peerId = peerId else {
return .single(false)
}
return strongSelf.startCall(context: context, peerId: peerId, isVideo: isVideo, internalId: uuid)
|> take(1)
|> map { result -> Bool in
return result
}
}
answerCallImpl = { [weak self] uuid in
@ -398,19 +409,39 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|> runOn(Queue.mainQueue())
let postbox = context.account.postbox
strongSelf.startCallDisposable.set((accessEnabledSignal
|> mapToSignal { accessEnabled -> Signal<Peer?, NoError> in
|> mapToSignal { accessEnabled -> Signal<(Peer?, String?), NoError> in
if !accessEnabled {
return .single(nil)
return .single((nil, nil))
}
return postbox.transaction { transaction -> (Peer?, String?) in
var foundLocalId: String?
transaction.enumerateDeviceContactImportInfoItems({ _, value in
if let value = value as? TelegramDeviceContactImportedData {
switch value {
case let .imported(data, _, importedPeerId):
if importedPeerId == peerId {
foundLocalId = data.localIdentifiers.first
return false
}
default:
break
}
}
return true
})
return (transaction.getPeer(peerId), foundLocalId)
}
return postbox.loadedPeerWithId(peerId)
|> take(1)
|> map(Optional.init)
}
|> deliverOnMainQueue).start(next: { peer in
|> deliverOnMainQueue).start(next: { peer, localContactId in
guard let strongSelf = self, let peer = peer else {
return
}
strongSelf.callKitIntegration?.startCall(context: context, peerId: peerId, isVideo: isVideo, displayTitle: peer.debugDisplayTitle)
var phoneNumber: String?
if let peer = peer as? TelegramUser, let phone = peer.phone {
phoneNumber = formatPhoneNumber(phone)
}
strongSelf.callKitIntegration?.startCall(context: context, peerId: peerId, phoneNumber: phoneNumber, localContactId: localContactId, isVideo: isVideo, displayTitle: peer.debugDisplayTitle)
}))
}
if let currentCall = self.currentCall {

View File

@ -3604,7 +3604,7 @@ func replayFinalState(
let namespace: ItemCollectionId.Namespace
var items: [ItemCollectionItem] = []
let info: StickerPackCollectionInfo
if case let .stickerSet(set, packs, documents) = apiSet {
if case let .stickerSet(set, packs, keywords, documents) = apiSet {
var indexKeysByFile: [MediaId: [MemoryBuffer]] = [:]
for pack in packs {
switch pack {
@ -3621,6 +3621,20 @@ func replayFinalState(
break
}
}
for keyword in keywords {
switch keyword {
case let .stickerKeyword(documentId, texts):
for text in texts {
let key = ValueBoxKey(text).toMemoryBuffer()
let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: documentId)
if indexKeysByFile[mediaId] == nil {
indexKeysByFile[mediaId] = [key]
} else {
indexKeysByFile[mediaId]!.append(key)
}
}
}
}
for apiDocument in documents {
if let file = telegramMediaFileFromApiDocument(apiDocument), let id = file.id {

View File

@ -1193,7 +1193,7 @@ public final class AccountViewTracker {
return account.postbox.transaction { transaction -> Void in
for result in results {
switch result {
case let .stickerSet(_, _, documents)?:
case let .stickerSet(_, _, _, documents)?:
for document in documents {
if let file = telegramMediaFileFromApiDocument(document) {
if transaction.getMedia(file.fileId) != nil {

View File

@ -249,7 +249,7 @@ private func pushDeviceContacts(postbox: Postbox, network: Network, importableCo
if let updatedData = importableContacts[number] {
if let value = value as? TelegramDeviceContactImportedData {
switch value {
case let .imported(data, _):
case let .imported(data, _, _):
if data != updatedData {
updatedDataIdentifiers.insert(identifier)
}
@ -289,7 +289,10 @@ private func pushDeviceContacts(postbox: Postbox, network: Network, importableCo
outer: for i in (0 ..< orderedPushIdentifiers.count).reversed() {
if let user = currentContactDetails[orderedPushIdentifiers[i]], case let .phoneNumber(number) = orderedPushIdentifiers[i], let data = importableContacts[number] {
if (user.firstName ?? "") == data.firstName && (user.lastName ?? "") == data.lastName {
transaction.setDeviceContactImportInfo(orderedPushIdentifiers[i].key, value: TelegramDeviceContactImportedData.imported(data: data, importedByCount: 0))
if data.localIdentifiers.contains("5DFF1D6F-8C0A-48C9-800D-F4BEC59C0E50") {
assert(true)
}
transaction.setDeviceContactImportInfo(orderedPushIdentifiers[i].key, value: TelegramDeviceContactImportedData.imported(data: data, importedByCount: 0, peerId: user.id))
orderedPushIdentifiers.remove(at: i)
continue outer
}
@ -334,6 +337,7 @@ private func pushDeviceContactData(postbox: Postbox, network: Network, contacts:
var addedContactPeerIds = Set<PeerId>()
var retryIndices = Set<Int>()
var importedCounts: [Int: Int32] = [:]
var peerIdByClientId: [Int64: PeerId] = [:]
switch result {
case let .importedContacts(imported, popularInvites, retryContacts, users):
let peers = users.map { TelegramUser(user: $0) as Peer }
@ -342,8 +346,10 @@ private func pushDeviceContactData(postbox: Postbox, network: Network, contacts:
})
for item in imported {
switch item {
case let .importedContact(userId, _):
addedContactPeerIds.insert(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)))
case let .importedContact(userId, clientId):
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
addedContactPeerIds.insert(peerId)
peerIdByClientId[clientId] = peerId
}
}
for item in retryContacts {
@ -363,7 +369,10 @@ private func pushDeviceContactData(postbox: Postbox, network: Network, contacts:
importedData = .retryLater
addedReimportAttempts[.phoneNumber(batch[i].0)] = timestamp
} else {
importedData = .imported(data: batch[i].1, importedByCount: importedCounts[i] ?? 0)
if batch[i].1.localIdentifiers.contains("5DFF1D6F-8C0A-48C9-800D-F4BEC59C0E50") {
assert(true)
}
importedData = .imported(data: batch[i].1, importedByCount: importedCounts[i] ?? 0, peerId: peerIdByClientId[Int64(i)])
}
transaction.setDeviceContactImportInfo(TelegramDeviceContactImportIdentifier.phoneNumber(batch[i].0).key, value: importedData)
}

View File

@ -147,7 +147,7 @@ private func fetchStickerPack(network: Network, info: StickerPackCollectionInfo)
switch result {
case .stickerSetNotModified:
break
case let .stickerSet(stickerSet, packs, documents):
case let .stickerSet(stickerSet, packs, keywords, documents):
updatedInfo = StickerPackCollectionInfo(apiSet: stickerSet, namespace: info.id.namespace)
var indexKeysByFile: [MediaId: [MemoryBuffer]] = [:]
for pack in packs {
@ -165,6 +165,20 @@ private func fetchStickerPack(network: Network, info: StickerPackCollectionInfo)
break
}
}
for keyword in keywords {
switch keyword {
case let .stickerKeyword(documentId, texts):
for text in texts {
let key = ValueBoxKey(text).toMemoryBuffer()
let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: documentId)
if indexKeysByFile[mediaId] == nil {
indexKeysByFile[mediaId] = [key]
} else {
indexKeysByFile[mediaId]!.append(key)
}
}
}
}
for apiDocument in documents {
if let file = telegramMediaFileFromApiDocument(apiDocument), let id = file.id {
@ -224,7 +238,7 @@ private func installRemoteStickerPacks(network: Network, infos: [StickerPackColl
archivedIds.insert(StickerPackCollectionInfo(apiSet: set, namespace: info.id.namespace).id)
case let .stickerSetMultiCovered(set, _):
archivedIds.insert(StickerPackCollectionInfo(apiSet: set, namespace: info.id.namespace).id)
case let .stickerSetFullCovered(set, _, _):
case let .stickerSetFullCovered(set, _, _, _):
archivedIds.insert(StickerPackCollectionInfo(apiSet: set, namespace: info.id.namespace).id)
}
}

View File

@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
public class Serialization: NSObject, MTSerialization {
public func currentLayer() -> UInt {
return 146
return 147
}
public func parseMessage(_ data: Data!) -> Any! {

View File

@ -227,7 +227,7 @@ func parsePreviewStickerSet(_ set: Api.StickerSetCovered, namespace: ItemCollect
}
}
return (info, items)
case let .stickerSetFullCovered(set, packs, documents):
case let .stickerSetFullCovered(set, packs, keywords, documents):
var indexKeysByFile: [MediaId: [MemoryBuffer]] = [:]
for pack in packs {
switch pack {
@ -244,6 +244,20 @@ func parsePreviewStickerSet(_ set: Api.StickerSetCovered, namespace: ItemCollect
break
}
}
for keyword in keywords {
switch keyword {
case let .stickerKeyword(documentId, texts):
for text in texts {
let key = ValueBoxKey(text).toMemoryBuffer()
let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: documentId)
if indexKeysByFile[mediaId] == nil {
indexKeysByFile[mediaId] = [key]
} else {
indexKeysByFile[mediaId]!.append(key)
}
}
}
}
let info = StickerPackCollectionInfo(apiSet: set, namespace: namespace)
var items: [StickerPackItem] = []

View File

@ -74,7 +74,7 @@ public func addSavedSticker(postbox: Postbox, network: Network, file: TelegramMe
switch result {
case .stickerSetNotModified:
break
case let .stickerSet(_, packs, _):
case let .stickerSet(_, packs, _, _):
var stringRepresentationsByFile: [MediaId: [String]] = [:]
for pack in packs {
switch pack {

View File

@ -3,20 +3,24 @@ import Postbox
public final class ImportableDeviceContactData: Equatable, PostboxCoding {
public let firstName: String
public let lastName: String
public let localIdentifiers: [String]
public init(firstName: String, lastName: String) {
public init(firstName: String, lastName: String, localIdentifiers: [String]) {
self.firstName = firstName
self.lastName = lastName
self.localIdentifiers = localIdentifiers
}
public init(decoder: PostboxDecoder) {
self.firstName = decoder.decodeStringForKey("f", orElse: "")
self.lastName = decoder.decodeStringForKey("l", orElse: "")
self.localIdentifiers = decoder.decodeStringArrayForKey("dis")
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeString(self.firstName, forKey: "f")
encoder.encodeString(self.lastName, forKey: "l")
encoder.encodeStringArray(self.localIdentifiers, forKey: "dis")
}
public static func ==(lhs: ImportableDeviceContactData, rhs: ImportableDeviceContactData) -> Bool {
@ -26,6 +30,9 @@ public final class ImportableDeviceContactData: Equatable, PostboxCoding {
if lhs.lastName != rhs.lastName {
return false
}
if lhs.localIdentifiers != rhs.localIdentifiers {
return false
}
return true
}
}

View File

@ -1,13 +1,13 @@
import Postbox
public enum TelegramDeviceContactImportedData: PostboxCoding {
case imported(data: ImportableDeviceContactData, importedByCount: Int32)
case imported(data: ImportableDeviceContactData, importedByCount: Int32, peerId: PeerId?)
case retryLater
public init(decoder: PostboxDecoder) {
switch decoder.decodeInt32ForKey("_t", orElse: 0) {
case 0:
self = .imported(data: decoder.decodeObjectForKey("d", decoder: { ImportableDeviceContactData(decoder: $0) }) as! ImportableDeviceContactData, importedByCount: decoder.decodeInt32ForKey("c", orElse: 0))
self = .imported(data: decoder.decodeObjectForKey("d", decoder: { ImportableDeviceContactData(decoder: $0) }) as! ImportableDeviceContactData, importedByCount: decoder.decodeInt32ForKey("c", orElse: 0), peerId: decoder.decodeOptionalInt64ForKey("pid").flatMap(PeerId.init))
case 1:
self = .retryLater
default:
@ -18,10 +18,15 @@ public enum TelegramDeviceContactImportedData: PostboxCoding {
public func encode(_ encoder: PostboxEncoder) {
switch self {
case let .imported(data, importedByCount):
case let .imported(data, importedByCount, peerId):
encoder.encodeInt32(0, forKey: "_t")
encoder.encodeObject(data, forKey: "d")
encoder.encodeInt32(importedByCount, forKey: "c")
if let peerId = peerId {
encoder.encodeInt64(peerId.toInt64(), forKey: "pid")
} else {
encoder.encodeNil(forKey: "pid")
}
case .retryLater:
encoder.encodeInt32(1, forKey: "_t")
}

View File

@ -53,7 +53,7 @@ func _internal_deviceContactsImportedByCount(postbox: Postbox, contacts: [(Strin
for (id, numbers) in contacts {
var maxCount: Int32 = 0
for number in numbers {
if let value = transaction.getDeviceContactImportInfo(TelegramDeviceContactImportIdentifier.phoneNumber(number).key) as? TelegramDeviceContactImportedData, case let .imported(_, importedByCount) = value {
if let value = transaction.getDeviceContactImportInfo(TelegramDeviceContactImportIdentifier.phoneNumber(number).key) as? TelegramDeviceContactImportedData, case let .imported(_, importedByCount, _) = value {
maxCount = max(maxCount, importedByCount)
}
}

View File

@ -69,5 +69,32 @@ public extension TelegramEngine {
}
|> ignoreValues
}
public func findPeerByLocalContactIdentifier(identifier: String) -> Signal<EnginePeer?, NoError> {
return self.account.postbox.transaction { transaction -> EnginePeer? in
var foundPeerId: PeerId?
transaction.enumerateDeviceContactImportInfoItems({ _, value in
if let value = value as? TelegramDeviceContactImportedData {
switch value {
case let .imported(data, _, peerId):
if data.localIdentifiers.contains(identifier) {
if let peerId = peerId {
foundPeerId = peerId
return false
}
}
default:
break
}
}
return true
})
if let foundPeerId = foundPeerId {
return transaction.getPeer(foundPeerId).flatMap(EnginePeer.init)
} else {
return nil
}
}
}
}
}

View File

@ -167,7 +167,7 @@ func _internal_createStickerSet(account: Account, title: String, shortName: Stri
switch result {
case .stickerSetNotModified:
return .complete()
case let .stickerSet(set, packs, documents):
case let .stickerSet(set, packs, keywords, documents):
let namespace: ItemCollectionId.Namespace
switch set {
case let .stickerSet(flags, _, _, _, _, _, _, _, _, _, _, _):
@ -195,6 +195,20 @@ func _internal_createStickerSet(account: Account, title: String, shortName: Stri
}
}
}
for keyword in keywords {
switch keyword {
case let .stickerKeyword(documentId, texts):
for text in texts {
let key = ValueBoxKey(text).toMemoryBuffer()
let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: documentId)
if indexKeysByFile[mediaId] == nil {
indexKeysByFile[mediaId] = [key]
} else {
indexKeysByFile[mediaId]!.append(key)
}
}
}
}
for apiDocument in documents {
if let file = telegramMediaFileFromApiDocument(apiDocument), let id = file.id {

View File

@ -52,7 +52,7 @@ func updatedRemoteStickerPack(postbox: Postbox, network: Network, reference: Sti
switch result {
case .stickerSetNotModified:
return .complete()
case let .stickerSet(set, packs, documents):
case let .stickerSet(set, packs, keywords, documents):
let namespace: ItemCollectionId.Namespace
switch set {
case let .stickerSet(flags, _, _, _, _, _, _, _, _, _, _, _):
@ -80,6 +80,20 @@ func updatedRemoteStickerPack(postbox: Postbox, network: Network, reference: Sti
}
}
}
for keyword in keywords {
switch keyword {
case let .stickerKeyword(documentId, texts):
for text in texts {
let key = ValueBoxKey(text).toMemoryBuffer()
let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: documentId)
if indexKeysByFile[mediaId] == nil {
indexKeysByFile[mediaId] = [key]
} else {
indexKeysByFile[mediaId]!.append(key)
}
}
}
}
for apiDocument in documents {
if let file = telegramMediaFileFromApiDocument(apiDocument), let id = file.id {

View File

@ -103,7 +103,7 @@ func _internal_stickerPacksAttachedToMedia(account: Account, media: AnyMediaRefe
|> map { result -> [StickerPackReference] in
return result.map { pack in
switch pack {
case let .stickerSetCovered(set, _), let .stickerSetMultiCovered(set, _), let .stickerSetFullCovered(set, _, _):
case let .stickerSetCovered(set, _), let .stickerSetMultiCovered(set, _), let .stickerSetFullCovered(set, _, _, _):
let info = StickerPackCollectionInfo(apiSet: set, namespace: Namespaces.ItemCollection.CloudStickerPacks)
return .id(id: info.id.id, accessHash: info.accessHash)
}

View File

@ -71,7 +71,7 @@ func _internal_requestStickerSet(postbox: Postbox, network: Network, reference:
switch result {
case .stickerSetNotModified:
return .complete()
case let .stickerSet(set, packs, documents):
case let .stickerSet(set, packs, keywords, documents):
info = StickerPackCollectionInfo(apiSet: set, namespace: Namespaces.ItemCollection.CloudStickerPacks)
switch set {
@ -95,6 +95,20 @@ func _internal_requestStickerSet(postbox: Postbox, network: Network, reference:
break
}
}
for keyword in keywords {
switch keyword {
case let .stickerKeyword(documentId, texts):
for text in texts {
let key = ValueBoxKey(text).toMemoryBuffer()
let mediaId = MediaId(namespace: Namespaces.Media.CloudFile, id: documentId)
if indexKeysByFile[mediaId] == nil {
indexKeysByFile[mediaId] = [key]
} else {
indexKeysByFile[mediaId]!.append(key)
}
}
}
}
for apiDocument in documents {
if let file = telegramMediaFileFromApiDocument(apiDocument), let id = file.id {
@ -167,7 +181,7 @@ func _internal_installStickerSetInteractively(account: Account, info: StickerPac
case let .stickerSetMultiCovered(set: set, covers: covers):
apiSet = set
apiDocuments = covers
case let .stickerSetFullCovered(set, _, documents):
case let .stickerSetFullCovered(set, _, _, documents):
apiSet = set
apiDocuments = documents
}

View File

@ -34,6 +34,7 @@ import DebugSettingsUI
import BackgroundTasks
import UIKitRuntimeUtils
import StoreKit
import PhoneNumberFormat
#if canImport(AppCenter)
import AppCenter
@ -1557,11 +1558,14 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
completion()
return
}
let phoneNumber = payloadJson["phoneNumber"] as? String
callKitIntegration.reportIncomingCall(
uuid: CallSessionManager.getStableIncomingUUID(stableId: callUpdate.callId),
stableId: callUpdate.callId,
handle: "\(callUpdate.peer.id.id._internalGetInt64Value())",
phoneNumber: phoneNumber.flatMap(formatPhoneNumber),
isVideo: false,
displayTitle: callUpdate.peer.debugDisplayTitle,
completion: { error in
@ -1745,52 +1749,65 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
}
if let contact = startCallContacts.first {
var processed = false
if let handle = contact.customIdentifier, handle.hasPrefix("tg") {
let string = handle.suffix(from: handle.index(handle.startIndex, offsetBy: 2))
if let userId = Int64(string) {
startCall(userId)
processed = true
}
let contactByIdentifier: Signal<EnginePeer?, NoError>
if let context = self.contextValue?.context, let contactIdentifier = contact.contactIdentifier {
contactByIdentifier = context.engine.contacts.findPeerByLocalContactIdentifier(identifier: contactIdentifier)
} else {
contactByIdentifier = .single(nil)
}
if !processed, let handle = contact.personHandle, let value = handle.value {
switch handle.type {
case .unknown:
if let userId = Int64(value) {
startCall(userId)
processed = true
}
case .phoneNumber:
let phoneNumber = cleanPhoneNumber(value)
if !phoneNumber.isEmpty {
guard let context = self.contextValue?.context else {
return true
let _ = (contactByIdentifier |> deliverOnMainQueue).start(next: { peerByContact in
var processed = false
if let peerByContact = peerByContact {
startCall(peerByContact.id.id._internalGetInt64Value())
processed = true
} else if let handle = contact.customIdentifier, handle.hasPrefix("tg") {
let string = handle.suffix(from: handle.index(handle.startIndex, offsetBy: 2))
if let userId = Int64(string) {
startCall(userId)
processed = true
}
}
if !processed, let handle = contact.personHandle, let value = handle.value {
switch handle.type {
case .unknown:
if let userId = Int64(value) {
startCall(userId)
processed = true
}
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Contacts.List(includePresences: false))
|> map { contactList -> PeerId? in
var result: PeerId?
for peer in contactList.peers {
if case let .user(peer) = peer, let peerPhoneNumber = peer.phone {
if matchPhoneNumbers(phoneNumber, peerPhoneNumber) {
result = peer.id
break
case .phoneNumber:
let phoneNumber = cleanPhoneNumber(value)
if !phoneNumber.isEmpty {
guard let context = self.contextValue?.context else {
return
}
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Contacts.List(includePresences: false))
|> map { contactList -> PeerId? in
var result: PeerId?
for peer in contactList.peers {
if case let .user(peer) = peer, let peerPhoneNumber = peer.phone {
if matchPhoneNumbers(phoneNumber, peerPhoneNumber) {
result = peer.id
break
}
}
}
return result
}
return result
|> deliverOnMainQueue).start(next: { peerId in
if let peerId = peerId {
startCall(peerId.id._internalGetInt64Value())
}
})
processed = true
}
|> deliverOnMainQueue).start(next: { peerId in
if let peerId = peerId {
startCall(peerId.id._internalGetInt64Value())
}
})
processed = true
}
default:
break
default:
break
}
}
}
})
return true
}
} else if let sendMessageIntent = userActivity.interaction?.intent as? INSendMessageIntent {
if let contact = sendMessageIntent.recipients?.first, let handle = contact.customIdentifier, handle.hasPrefix("tg") {

View File

@ -1496,8 +1496,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if packReferences.count > 1 {
items.tip = .animatedEmoji(text: presentationData.strings.ChatContextMenu_EmojiSet(Int32(packReferences.count)), arguments: nil, file: nil, action: action)
} else if let reference = packReferences.first {
items.tipSignal = context.engine.stickers.loadedStickerPack(reference: reference, forceActualized: false)
|> delay(1.0, queue: .mainQueue())
var tipSignal: Signal<LoadedStickerPack, NoError>
tipSignal = context.engine.stickers.loadedStickerPack(reference: reference, forceActualized: false)
items.tipSignal = tipSignal
|> filter { result in
if case .result = result {
return true

View File

@ -499,7 +499,10 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode {
var emojiStatus: PeerEmojiStatus?
if let user = interfaceState.renderedPeer?.peer as? TelegramUser, let emojiStatusValue = user.emojiStatus {
emojiStatus = emojiStatusValue
if user.isFake || user.isScam {
} else {
emojiStatus = emojiStatusValue
}
}
/*#if DEBUG

View File

@ -150,12 +150,12 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
}
if peer.id != self.context.account.peerId {
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 })
if let user = peer as? TelegramUser, let emojiStatus = user.emojiStatus {
titleCredibilityIcon = .emojiStatus(emojiStatus)
} else if peer.isFake {
if peer.isFake {
titleCredibilityIcon = .fake
} else if peer.isScam {
titleCredibilityIcon = .scam
} else if let user = peer as? TelegramUser, let emojiStatus = user.emojiStatus {
titleCredibilityIcon = .emojiStatus(emojiStatus)
} else if peer.isVerified {
titleCredibilityIcon = .verified
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled {

View File

@ -429,15 +429,20 @@ private final class DeviceContactDataManagerPrivateImpl {
for (stableId, basicData) in self.stableIdToBasicContactData {
for phoneNumber in basicData.phoneNumbers {
var replace = false
var currentLocalIdentifiers: [String] = []
if let current = importableContactData[phoneNumber.value] {
if stableId < current.0 {
replace = true
currentLocalIdentifiers = current.1.localIdentifiers
}
} else {
replace = true
}
if replace {
importableContactData[phoneNumber.value] = (stableId, ImportableDeviceContactData(firstName: basicData.firstName, lastName: basicData.lastName))
if !currentLocalIdentifiers.contains(stableId) {
currentLocalIdentifiers.append(stableId)
}
importableContactData[phoneNumber.value] = (stableId, ImportableDeviceContactData(firstName: basicData.firstName, lastName: basicData.lastName, localIdentifiers: currentLocalIdentifiers))
}
}
}

View File

@ -2311,13 +2311,13 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 })
let credibilityIcon: CredibilityIcon
if let user = peer as? TelegramUser, let emojiStatus = user.emojiStatus {
credibilityIcon = .emojiStatus(emojiStatus)
} else if let peer = peer {
if let peer = peer {
if peer.isFake {
credibilityIcon = .fake
} else if peer.isScam {
credibilityIcon = .scam
} else if let user = peer as? TelegramUser, let emojiStatus = user.emojiStatus {
credibilityIcon = .emojiStatus(emojiStatus)
} else if peer.isVerified {
credibilityIcon = .verified
} else if peer.isPremium && !premiumConfiguration.isPremiumDisabled && (peer.id != self.context.account.peerId || self.isSettings) {

View File

@ -5,6 +5,7 @@
#import "NSWeakReference.h"
@interface UIViewControllerPresentingProxy : UIViewController
@property (nonatomic, copy) void (^dismiss)();
@ -139,6 +140,18 @@ static bool notyfyingShiftState = false;
@end
@interface UIWindow (Telegram)
@end
@implementation UIWindow (Telegram)
- (instancetype)_65087dc8_initWithFrame:(CGRect)frame {
return [self _65087dc8_initWithFrame:frame];
}
@end
@protocol UIRemoteKeyboardWindowProtocol
+ (UIWindow * _Nullable)remoteKeyboardWindowForScreen:(UIScreen * _Nullable)screen create:(BOOL)create;
@ -161,7 +174,7 @@ static bool notyfyingShiftState = false;
[RuntimeUtils swizzleInstanceMethodOfClass:[UIViewController class] currentSelector:@selector(presentViewController:animated:completion:) newSelector:@selector(_65087dc8_presentViewController:animated:completion:)];
[RuntimeUtils swizzleInstanceMethodOfClass:[UIViewController class] currentSelector:@selector(setNeedsStatusBarAppearanceUpdate) newSelector:@selector(_65087dc8_setNeedsStatusBarAppearanceUpdate)];
[RuntimeUtils swizzleClassMethodOfClass:NSClassFromString(@"UIRemoteKeyboardWindow") currentSelector:NSSelectorFromString(@"remoteKeyboardWindowForScreen:create:") newSelector:NSSelectorFromString(@"_65087dc8_remoteKeyboardWindowForScreen:create:")];
[RuntimeUtils swizzleInstanceMethodOfClass:[UIWindow class] currentSelector:@selector(initWithFrame:) newSelector:@selector(_65087dc8_initWithFrame:)];
if (@available(iOS 15.0, *)) {
[RuntimeUtils swizzleInstanceMethodOfClass:[CADisplayLink class] currentSelector:@selector(setPreferredFrameRateRange:) newSelector:@selector(_65087dc8_setPreferredFrameRateRange:)];
@ -304,7 +317,8 @@ static bool notyfyingShiftState = false;
if (!windowClass) {
return nil;
}
return [(id<UIRemoteKeyboardWindowProtocol>)windowClass remoteKeyboardWindowForScreen:[UIScreen mainScreen] create:false];
UIWindow *result = [(id<UIRemoteKeyboardWindowProtocol>)windowClass remoteKeyboardWindowForScreen:[UIScreen mainScreen] create:false];
return result;
}
@end