diff --git a/TelegramUI/CallRatingController.swift b/TelegramUI/CallRatingController.swift index 11b9bdb640..06dda015dd 100644 --- a/TelegramUI/CallRatingController.swift +++ b/TelegramUI/CallRatingController.swift @@ -321,22 +321,35 @@ private final class CallRatingAlertContentNode: AlertContentNode { } } -private func rateCallAndSendLogs(account: Account, report: ReportCallRating, starsCount: Int, comment: String, includeLogs: Bool) -> Signal { - var signal = rateCall(account: account, report: report, starsCount: Int32(starsCount), comment: comment) - if includeLogs { - let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: 4244000) -// signal = signal -// |> then( -// enqueueMessages(account: account, peerId: peerId, messages: EnqueueMessage.message(text: "", attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)) -// |> map { _ -> Void in -// -// } -// ) +private func rateCallAndSendLogs(account: Account, callId: CallId, starsCount: Int, comment: String, includeLogs: Bool) -> Signal { + let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: 4244000) + + var rateSignal = rateCall(account: account, callId: callId, starsCount: Int32(starsCount), comment: comment) + if !comment.isEmpty { + rateSignal = rateSignal + |> then(enqueueMessages(account: account, peerId: peerId, messages: [.message(text: comment, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil)]) + |> mapToSignal({ _ -> Signal in + return .single(Void()) + })) + } + if includeLogs { + let id = arc4random64() + let name = "\(callId.id)_\(callId.accessHash).log" + let path = callLogsPath(account: account) + "/" + name + let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: id), partialReference: nil, resource: LocalFileReferenceMediaResource(localFilePath: path, randomId: id), previewRepresentations: [], mimeType: "application/text", size: nil, attributes: [.FileName(fileName: name)]) + let message = EnqueueMessage.message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil) + + return rateSignal + |> then(enqueueMessages(account: account, peerId: peerId, messages: [message]) + |> mapToSignal({ _ -> Signal in + return .single(Void()) + })) + } else { + return rateSignal } - return signal } -func callRatingController(account: Account, report: ReportCallRating, present: @escaping (ViewController) -> Void) -> AlertController { +func callRatingController(account: Account, callId: CallId, present: @escaping (ViewController) -> Void) -> AlertController { let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } let theme = presentationData.theme let strings = presentationData.strings @@ -350,13 +363,13 @@ func callRatingController(account: Account, report: ReportCallRating, present: @ if let contentNode = contentNode, let rating = contentNode.rating { if rating < 4 { let controller = textAlertController(account: account, title: strings.Call_ReportIncludeLog, text: strings.Call_ReportIncludeLogDescription, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Call_ReportSkip, action: { - let _ = rateCallAndSendLogs(account: account, report: report, starsCount: rating, comment: contentNode.comment, includeLogs: false).start() + let _ = rateCallAndSendLogs(account: account, callId: callId, starsCount: rating, comment: contentNode.comment, includeLogs: false).start() }), TextAlertAction(type: .defaultAction, title: presentationData.strings.Call_ReportSend, action: { - let _ = rateCallAndSendLogs(account: account, report: report, starsCount: rating, comment: contentNode.comment, includeLogs: true).start() + let _ = rateCallAndSendLogs(account: account, callId: callId, starsCount: rating, comment: contentNode.comment, includeLogs: true).start() })]) present(controller) } else { - let _ = rateCallAndSendLogs(account: account, report: report, starsCount: rating, comment: contentNode.comment, includeLogs: false).start + let _ = rateCallAndSendLogs(account: account, callId: callId, starsCount: rating, comment: contentNode.comment, includeLogs: false).start } } })] diff --git a/TelegramUI/ChatController.swift b/TelegramUI/ChatController.swift index ddef532cb1..130a2aaae7 100644 --- a/TelegramUI/ChatController.swift +++ b/TelegramUI/ChatController.swift @@ -1086,9 +1086,9 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal self?.present(controller, in: .window(.root), with: arguments) }) } - }, rateCall: { [weak self] message in + }, rateCall: { [weak self] message, callId in if let strongSelf = self { - let controller = callRatingController(account: strongSelf.account, report: ReportCallRating(id: 0, accessHash: 0), present: { [weak self] controller in + let controller = callRatingController(account: strongSelf.account, callId: callId, present: { [weak self] controller in if let strongSelf = self { strongSelf.present(controller, in: .window(.root)) } diff --git a/TelegramUI/ChatControllerInteraction.swift b/TelegramUI/ChatControllerInteraction.swift index b1f09822a2..85519245a6 100644 --- a/TelegramUI/ChatControllerInteraction.swift +++ b/TelegramUI/ChatControllerInteraction.swift @@ -81,7 +81,7 @@ public final class ChatControllerInteraction { let navigateToFirstDateMessage: (Int32) -> Void let requestRedeliveryOfFailedMessages: (MessageId) -> Void let addContact: (String) -> Void - let rateCall: (Message) -> Void + let rateCall: (Message, CallId) -> Void let requestSelectMessagePollOption: (MessageId, Data) -> Void let requestMessageUpdate: (MessageId) -> Void @@ -94,7 +94,7 @@ public final class ChatControllerInteraction { var automaticMediaDownloadSettings: AutomaticMediaDownloadSettings var pollActionState: ChatInterfacePollActionState - init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool) -> Void, sendGif: @escaping (FileMediaReference) -> Void, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message) -> Void, requestSelectMessagePollOption: @escaping (MessageId, Data) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: AutomaticMediaDownloadSettings, pollActionState: ChatInterfacePollActionState) { + init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool) -> Void, sendGif: @escaping (FileMediaReference) -> Void, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOption: @escaping (MessageId, Data) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: AutomaticMediaDownloadSettings, pollActionState: ChatInterfacePollActionState) { self.openMessage = openMessage self.openPeer = openPeer self.openPeerMention = openPeerMention diff --git a/TelegramUI/ChatInterfaceStateContextMenus.swift b/TelegramUI/ChatInterfaceStateContextMenus.swift index 45141d08d8..fefaf410d3 100644 --- a/TelegramUI/ChatInterfaceStateContextMenus.swift +++ b/TelegramUI/ChatInterfaceStateContextMenus.swift @@ -513,9 +513,27 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState: } if data.messageActions.options.contains(.rateCall) { - actions.append(.sheet(ChatMessageContextMenuSheetAction(color: .accent, title: chatPresentationInterfaceState.strings.Call_RateCall, action: { - let _ = controllerInteraction.rateCall(message) - }))) + var callId: CallId? + for media in message.media { + if let action = media as? TelegramMediaAction, case let .phoneCall(id, discardReason, _) = action.action { + if discardReason != .busy && discardReason != .missed { + if let logName = callLogNameForId(id: id, account: account) { + let start = logName.index(logName.startIndex, offsetBy: "\(id)".count + 1) + let end = logName.index(logName.endIndex, offsetBy: -4) + let accessHash = logName[start.. ChatMessageForwardInfoNode)? @@ -263,6 +338,27 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView { } videoApply(videoLayoutData, transition) + if let updatedShareButtonNode = updatedShareButtonNode { + if updatedShareButtonNode !== strongSelf.shareButtonNode { + if let shareButtonNode = strongSelf.shareButtonNode { + shareButtonNode.removeFromSupernode() + } + strongSelf.shareButtonNode = updatedShareButtonNode + strongSelf.addSubnode(updatedShareButtonNode) + updatedShareButtonNode.addTarget(strongSelf, action: #selector(strongSelf.shareButtonPressed), forControlEvents: .touchUpInside) + } + if let updatedShareButtonBackground = updatedShareButtonBackground { + strongSelf.shareButtonNode?.setBackgroundImage(updatedShareButtonBackground, for: [.normal]) + } + } else if let shareButtonNode = strongSelf.shareButtonNode { + shareButtonNode.removeFromSupernode() + strongSelf.shareButtonNode = nil + } + + if let shareButtonNode = strongSelf.shareButtonNode { + shareButtonNode.frame = CGRect(origin: CGPoint(x: videoFrame.maxX - 7.0, y: videoFrame.maxY - 54.0), size: CGSize(width: 29.0, height: 29.0)) + } + if let updatedReplyBackgroundNode = updatedReplyBackgroundNode { if strongSelf.replyBackgroundNode == nil { strongSelf.replyBackgroundNode = updatedReplyBackgroundNode @@ -426,6 +522,21 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView { } } + @objc func shareButtonPressed() { + if let item = self.item { + if item.content.firstMessage.id.peerId == item.account.peerId { + for attribute in item.content.firstMessage.attributes { + if let attribute = attribute as? SourceReferenceMessageAttribute { + item.controllerInteraction.navigateToMessage(item.content.firstMessage.id, attribute.messageId) + break + } + } + } else { + item.controllerInteraction.openMessageShareMenu(item.message.id) + } + } + } + @objc func swipeToReplyGesture(_ recognizer: ChatSwipeToReplyRecognizer) { switch recognizer.state { case .began: @@ -490,6 +601,9 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView { } override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + if let shareButtonNode = self.shareButtonNode, shareButtonNode.frame.contains(point) { + return shareButtonNode.view + } if !self.bounds.contains(point) { return nil } diff --git a/TelegramUI/ChatRecentActionsControllerNode.swift b/TelegramUI/ChatRecentActionsControllerNode.swift index 80d5592cff..0b5e6118b6 100644 --- a/TelegramUI/ChatRecentActionsControllerNode.swift +++ b/TelegramUI/ChatRecentActionsControllerNode.swift @@ -350,7 +350,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }, requestRedeliveryOfFailedMessages: { _ in }, addContact: { _ in - }, rateCall: { _ in + }, rateCall: { _, _ in }, requestSelectMessagePollOption: { _, _ in }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: { diff --git a/TelegramUI/ContactsController.swift b/TelegramUI/ContactsController.swift index 1fae1d7bf8..ae0202d993 100644 --- a/TelegramUI/ContactsController.swift +++ b/TelegramUI/ContactsController.swift @@ -221,32 +221,35 @@ public class ContactsController: ViewController { } @objc func addPressed() { - let _ = (DeviceAccess.contacts + let _ = (DeviceAccess.authorizationStatus(account: self.account, subject: .contacts) |> take(1) - |> deliverOnMainQueue).start(next: { [weak self] value in + |> deliverOnMainQueue).start(next: { [weak self] status in guard let strongSelf = self else { return } - if let value = value, value { - let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: "", lastName: "", phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!!$_", value: "")]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: []) - strongSelf.present(deviceContactInfoController(account: strongSelf.account, subject: .create(peer: nil, contactData: contactData, completion: { peer, stableId, contactData in - guard let strongSelf = self else { - return - } - if let peer = peer { - if let infoController = peerInfoController(account: strongSelf.account, peer: peer) { - (strongSelf.navigationController as? NavigationController)?.pushViewController(infoController) + switch status { + case .allowed: + let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: "", lastName: "", phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!!$_", value: "")]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: []) + strongSelf.present(deviceContactInfoController(account: strongSelf.account, subject: .create(peer: nil, contactData: contactData, completion: { peer, stableId, contactData in + guard let strongSelf = self else { + return } - } else { - (strongSelf.navigationController as? NavigationController)?.pushViewController(deviceContactInfoController(account: strongSelf.account, subject: .vcard(nil, stableId, contactData))) - } - })), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) - } else { - let presentationData = strongSelf.presentationData - strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: presentationData.strings.AccessDenied_Title, text: presentationData.strings.Contacts_AccessDeniedError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_NotNow, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.AccessDenied_Settings, action: { - self?.account.telegramApplicationContext.applicationBindings.openSettings() - })]), in: .window(.root)) + if let peer = peer { + if let infoController = peerInfoController(account: strongSelf.account, peer: peer) { + (strongSelf.navigationController as? NavigationController)?.pushViewController(infoController) + } + } else { + (strongSelf.navigationController as? NavigationController)?.pushViewController(deviceContactInfoController(account: strongSelf.account, subject: .vcard(nil, stableId, contactData))) + } + })), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + case .notDetermined: + DeviceAccess.authorizeAccess(to: .contacts, account: strongSelf.account) + default: + let presentationData = strongSelf.presentationData + strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: presentationData.strings.AccessDenied_Title, text: presentationData.strings.Contacts_AccessDeniedError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_NotNow, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.AccessDenied_Settings, action: { + self?.account.telegramApplicationContext.applicationBindings.openSettings() + })]), in: .window(.root)) } }) } diff --git a/TelegramUI/OngoingCallContext.swift b/TelegramUI/OngoingCallContext.swift index 4dc22dd8cb..35ae9e6c4b 100644 --- a/TelegramUI/OngoingCallContext.swift +++ b/TelegramUI/OngoingCallContext.swift @@ -11,7 +11,23 @@ private func callConnectionDescription(_ connection: CallSessionConnection) -> O private let callLogsLimit = 20 -private func callLogsPath(account: Account) -> String { +func callLogNameForId(id: Int64, account: Account) -> String? { + let path = callLogsPath(account: account) + let namePrefix = "\(id)_" + + if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: path), includingPropertiesForKeys: [], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) { + for url in enumerator { + if let url = url as? URL { + if url.lastPathComponent.hasPrefix(namePrefix) { + return url.lastPathComponent + } + } + } + } + return nil +} + +func callLogsPath(account: Account) -> String { return account.basePath + "/calls" } @@ -115,7 +131,7 @@ final class OngoingCallContext { let internalId: CallSessionInternalId private let queue = Queue() - private let postbox: Postbox + private let account: Account private let callSessionManager: CallSessionManager private var contextRef: Unmanaged? @@ -149,12 +165,12 @@ final class OngoingCallContext { return OngoingCallThreadLocalContext.maxLayer() } - init(account: Account, callSessionManager: CallSessionManager, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal, serializedData: String?, dataSaving: VoiceCallDataSaving, derivedState: VoipDerivedState, logPath: String) { + init(account: Account, callSessionManager: CallSessionManager, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal, serializedData: String?, dataSaving: VoiceCallDataSaving, derivedState: VoipDerivedState) { let _ = setupLogs OngoingCallThreadLocalContext.applyServerConfig(serializedData) self.internalId = internalId - self.postbox = account.postbox + self.account = account self.callSessionManager = callSessionManager let queue = self.queue @@ -168,7 +184,7 @@ final class OngoingCallContext { break } } - let context = OngoingCallThreadLocalContext(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForType(initialNetworkType), dataSaving: ongoingDataSavingForType(dataSaving), logPath: logPath, derivedState: derivedState.data) + let context = OngoingCallThreadLocalContext(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForType(initialNetworkType), dataSaving: ongoingDataSavingForType(dataSaving), derivedState: derivedState.data) self.contextRef = Unmanaged.passRetained(context) context.stateChanged = { [weak self] state in self?.contextState.set(.single(state)) @@ -194,6 +210,8 @@ final class OngoingCallContext { context.setNetworkType(ongoingNetworkTypeForType(networkType)) } }) + + cleanupCallLogs(account: account) } deinit { @@ -215,13 +233,14 @@ final class OngoingCallContext { } } - func start(key: Data, isOutgoing: Bool, connections: CallSessionConnectionSet, maxLayer: Int32, allowP2P: Bool, audioSessionActive: Signal) { + func start(key: Data, isOutgoing: Bool, connections: CallSessionConnectionSet, maxLayer: Int32, allowP2P: Bool, audioSessionActive: Signal, logName: String) { + var logPath = logName.isEmpty ? "" : callLogsPath(account: self.account) + "/" + logName + ".log" self.audioSessionDisposable.set((audioSessionActive |> filter { $0 } |> take(1)).start(next: { [weak self] _ in if let strongSelf = self { strongSelf.withContext { context in - context.start(withKey: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescription(connections.primary), alternativeConnections: connections.alternatives.map(callConnectionDescription), maxLayer: maxLayer, allowP2P: allowP2P) + context.start(withKey: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescription(connections.primary), alternativeConnections: connections.alternatives.map(callConnectionDescription), maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath) } } })) @@ -231,7 +250,7 @@ final class OngoingCallContext { self.withContext { context in context.stop() let derivedState = context.getDerivedState() - let _ = updateVoipDerivedStateInteractively(postbox: self.postbox, { _ in + let _ = updateVoipDerivedStateInteractively(postbox: self.account.postbox, { _ in return VoipDerivedState(data: derivedState) }).start() } diff --git a/TelegramUI/OngoingCallThreadLocalContext.h b/TelegramUI/OngoingCallThreadLocalContext.h index a15897f048..23093ffdda 100644 --- a/TelegramUI/OngoingCallThreadLocalContext.h +++ b/TelegramUI/OngoingCallThreadLocalContext.h @@ -63,8 +63,8 @@ typedef NS_ENUM(int32_t, OngoingCallDataSaving) { @property (nonatomic, copy) void (^ _Nullable signalBarsChanged)(int32_t); @property (nonatomic, copy) void (^ _Nullable callEnded)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile); -- (instancetype _Nonnull)initWithQueue:(id _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving logPath:(NSString * _Nonnull)logPath derivedState:(NSData * _Nonnull)derivedState; -- (void)startWithKey:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P; +- (instancetype _Nonnull)initWithQueue:(id _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving derivedState:(NSData * _Nonnull)derivedState; +- (void)startWithKey:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath; - (void)stop; - (NSString * _Nullable)debugInfo; diff --git a/TelegramUI/OngoingCallThreadLocalContext.mm b/TelegramUI/OngoingCallThreadLocalContext.mm index ed56315222..780e4de42c 100644 --- a/TelegramUI/OngoingCallThreadLocalContext.mm +++ b/TelegramUI/OngoingCallThreadLocalContext.mm @@ -128,7 +128,6 @@ static void withContext(int32_t contextId, void (^f)(OngoingCallThreadLocalConte NSTimeInterval _callConnectTimeout; NSTimeInterval _callPacketTimeout; int32_t _dataSavingMode; - NSString *_logPath; tgvoip::VoIPController *_controller; @@ -215,7 +214,7 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) { return tgvoip::VoIPController::GetConnectionMaxLayer(); } -- (instancetype _Nonnull)initWithQueue:(id _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving logPath:(NSString * _Nonnull)logPath derivedState:(NSData * _Nonnull)derivedState { +- (instancetype _Nonnull)initWithQueue:(id _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving derivedState:(NSData * _Nonnull)derivedState { self = [super init]; if (self != nil) { _queue = queue; @@ -228,7 +227,6 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) { _callPacketTimeout = 10.0; _dataSavingMode = callControllerDataSavingForType(dataSaving); _networkType = networkType; - _logPath = logPath; _controller = new tgvoip::VoIPController(); _controller->implData = (void *)((intptr_t)_contextId); @@ -271,7 +269,7 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) { } } -- (void)startWithKey:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P { +- (void)startWithKey:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath { std::vector endpoints; NSArray *connections = [@[primaryConnection] arrayByAddingObjectsFromArray:alternativeConnections]; for (OngoingCallConnectionDescription *connection in connections) { @@ -293,7 +291,7 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) { } tgvoip::VoIPController::Config config(_callConnectTimeout, _callPacketTimeout, _dataSavingMode, false, true, true); - config.logFilePath = _logPath.length > 0 ? std::string(_logPath.UTF8String) : ""; + config.logFilePath = logPath.length > 0 ? std::string(logPath.UTF8String) : ""; config.statsDumpFilePath = ""; if (_controller != nil) { diff --git a/TelegramUI/OpenChatMessage.swift b/TelegramUI/OpenChatMessage.swift index 06233af06f..a0d86b0d00 100644 --- a/TelegramUI/OpenChatMessage.swift +++ b/TelegramUI/OpenChatMessage.swift @@ -43,13 +43,14 @@ private func chatMessageGalleryControllerData(account: Account, message: Message } else if let image = media as? TelegramMediaImage { galleryMedia = image } else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content, !excludeWebPageMedia { - if ["photo", "document", "video", "gif", "audio", "voice"].contains(content.type) { if let file = content.file { galleryMedia = file } else if let image = content.image { - galleryMedia = image + if ["photo", "document", "video", "gif"].contains(content.type) { + galleryMedia = image + } } - } + if let instantPage = content.instantPage, let galleryMedia = galleryMedia { switch instantPageType(of: content) { case .album: diff --git a/TelegramUI/OverlayPlayerControllerNode.swift b/TelegramUI/OverlayPlayerControllerNode.swift index e5022051b2..e75a8af3e0 100644 --- a/TelegramUI/OverlayPlayerControllerNode.swift +++ b/TelegramUI/OverlayPlayerControllerNode.swift @@ -68,7 +68,7 @@ final class OverlayPlayerControllerNode: ViewControllerTracingNode, UIGestureRec }, navigateToFirstDateMessage: { _ in }, requestRedeliveryOfFailedMessages: { _ in }, addContact: { _ in - }, rateCall: { _ in + }, rateCall: { _, _ in }, requestSelectMessagePollOption: { _, _ in }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: { diff --git a/TelegramUI/PeerMediaCollectionController.swift b/TelegramUI/PeerMediaCollectionController.swift index 4355f3c555..8409353c41 100644 --- a/TelegramUI/PeerMediaCollectionController.swift +++ b/TelegramUI/PeerMediaCollectionController.swift @@ -248,7 +248,7 @@ public class PeerMediaCollectionController: TelegramController { }, navigateToFirstDateMessage: { _ in }, requestRedeliveryOfFailedMessages: { _ in }, addContact: { _ in - }, rateCall: { _ in + }, rateCall: { _, _ in }, requestSelectMessagePollOption: { _, _ in }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: { diff --git a/TelegramUI/PresentationCall.swift b/TelegramUI/PresentationCall.swift index 20ff4d73fd..f9ec66de51 100644 --- a/TelegramUI/PresentationCall.swift +++ b/TelegramUI/PresentationCall.swift @@ -232,7 +232,7 @@ public final class PresentationCall { self.isOutgoing = isOutgoing self.peer = peer - self.ongoingContext = OngoingCallContext(account: account, callSessionManager: self.callSessionManager, internalId: self.internalId, proxyServer: proxyServer, initialNetworkType: currentNetworkType, updatedNetworkType: updatedNetworkType, serializedData: serializedData, dataSaving: dataSaving, derivedState: derivedState, logPath: "") + self.ongoingContext = OngoingCallContext(account: account, callSessionManager: self.callSessionManager, internalId: self.internalId, proxyServer: proxyServer, initialNetworkType: currentNetworkType, updatedNetworkType: updatedNetworkType, serializedData: serializedData, dataSaving: dataSaving, derivedState: derivedState) var didReceiveAudioOutputs = false self.sessionStateDisposable = (callSessionManager.callState(internalId: internalId) @@ -428,7 +428,7 @@ public final class PresentationCall { presentationState = .terminated(reason) case let .requesting(ringing): presentationState = .requesting(ringing) - case let .active(_, keyVisualHash, _, _, _): + case let .active(_, _, keyVisualHash, _, _, _): if let callContextState = callContextState { switch callContextState { case .initializing: @@ -456,10 +456,11 @@ public final class PresentationCall { if let _ = audioSessionControl { self.audioSessionShouldBeActive.set(true) } - case let .active(key, _, connections, maxLayer, allowsP2P): + case let .active(id, key, _, connections, maxLayer, allowsP2P): self.audioSessionShouldBeActive.set(true) if let _ = audioSessionControl, !wasActive || previousControl == nil { - self.ongoingContext.start(key: key, isOutgoing: sessionState.isOutgoing, connections: connections, maxLayer: maxLayer, allowP2P: allowsP2P, audioSessionActive: self.audioSessionActive.get()) + let logName = "\(id.id)_\(id.accessHash)" + self.ongoingContext.start(key: key, isOutgoing: sessionState.isOutgoing, connections: connections, maxLayer: maxLayer, allowP2P: allowsP2P, audioSessionActive: self.audioSessionActive.get(), logName: logName) if sessionState.isOutgoing { self.callKitIntegration?.reportOutgoingCallConnected(uuid: sessionState.id, at: Date()) } diff --git a/TelegramUI/ShareController.swift b/TelegramUI/ShareController.swift index 43263e89ee..f004eee332 100644 --- a/TelegramUI/ShareController.swift +++ b/TelegramUI/ShareController.swift @@ -275,7 +275,13 @@ public final class ShareController: ViewController { else if let chatPeer = message.peers[message.id.peerId] as? TelegramChannel, messages.count == 1 || sameGroupingKey { if message.id.namespace == Namespaces.Message.Cloud, let addressName = chatPeer.addressName, !addressName.isEmpty { self.defaultAction = ShareControllerAction(title: self.presentationData.strings.ShareMenu_CopyShareLink, action: { [weak self] in - UIPasteboard.general.string = "https://t.me/\(addressName)/\(message.id.id)" + let _ = (exportMessageLink(account: account, peerId: chatPeer.id, messageId: message.id) + |> map { result -> String in + return result ?? "https://t.me/\(addressName)/\(message.id.id)" + } + |> deliverOnMainQueue).start(next: { link in + UIPasteboard.general.string = link + }) self?.controllerNode.cancel?() }) } diff --git a/TelegramUI/ThemeSettingsChatPreviewItem.swift b/TelegramUI/ThemeSettingsChatPreviewItem.swift index 7589b1d613..0f3f1b2d3b 100644 --- a/TelegramUI/ThemeSettingsChatPreviewItem.swift +++ b/TelegramUI/ThemeSettingsChatPreviewItem.swift @@ -102,7 +102,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode { }, navigateToFirstDateMessage: { _ in }, requestRedeliveryOfFailedMessages: { _ in }, addContact: { _ in - }, rateCall: { _ in + }, rateCall: { _, _ in }, requestSelectMessagePollOption: { _, _ in }, requestMessageUpdate: { _ in }, cancelInteractiveKeyboardGestures: {