diff --git a/TelegramUI.xcodeproj/project.pbxproj b/TelegramUI.xcodeproj/project.pbxproj index d0029a7986..47e84e793e 100644 --- a/TelegramUI.xcodeproj/project.pbxproj +++ b/TelegramUI.xcodeproj/project.pbxproj @@ -993,6 +993,7 @@ D0EC6EA61EB9FC2400EBF1C3 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D07551901DDA4FC70073E051 /* libc++.tbd */; }; D0EC6EBD1EBA100F00EBF1C3 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0EC6EBC1EBA100F00EBF1C3 /* CoreAudio.framework */; }; D0EC6FFD1EBA1F2400EBF1C3 /* OngoingCallThreadLocalContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = D0EC6FFC1EBA1F2400EBF1C3 /* OngoingCallThreadLocalContext.mm */; }; + D0EEE9A12165585F001292A6 /* DocumentPreviewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0EEE9A02165585F001292A6 /* DocumentPreviewController.swift */; }; D0F0AAE01EC1E12C005EE2A5 /* PresentationCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F0AADF1EC1E12C005EE2A5 /* PresentationCall.swift */; }; D0F0AAE21EC20EF8005EE2A5 /* CallControllerStatusNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F0AAE11EC20EF8005EE2A5 /* CallControllerStatusNode.swift */; }; D0F0AAE41EC21AAA005EE2A5 /* CallControllerButtonsNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F0AAE31EC21AAA005EE2A5 /* CallControllerButtonsNode.swift */; }; @@ -1970,6 +1971,7 @@ D0EC6FFC1EBA1F2400EBF1C3 /* OngoingCallThreadLocalContext.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = OngoingCallThreadLocalContext.mm; sourceTree = ""; }; D0ED5D4A1DC806D7007CBB15 /* ApplicationSpecificData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApplicationSpecificData.swift; sourceTree = ""; }; D0EE97191D88BCA0006C18E1 /* ChatInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatInfo.swift; sourceTree = ""; }; + D0EEE9A02165585F001292A6 /* DocumentPreviewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentPreviewController.swift; sourceTree = ""; }; D0EF40DC1E72F00E000DFCD4 /* SelectivePrivacySettingsPeersController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectivePrivacySettingsPeersController.swift; sourceTree = ""; }; D0EF40DE1E73100D000DFCD4 /* ChatHistoryNavigationStack.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatHistoryNavigationStack.swift; sourceTree = ""; }; D0EFD8951DDE8249009E508A /* LegacyLocationPicker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyLocationPicker.swift; sourceTree = ""; }; @@ -3779,6 +3781,14 @@ name = "Peer Info"; sourceTree = ""; }; + D0EEE99F2165583B001292A6 /* Document */ = { + isa = PBXGroup; + children = ( + D0EEE9A02165585F001292A6 /* DocumentPreviewController.swift */, + ); + name = Document; + sourceTree = ""; + }; D0F53BF51E79592300117362 /* Sign Up */ = { isa = PBXGroup; children = ( @@ -4132,6 +4142,7 @@ D0B7F8DF1D8A17D20045D939 /* Collection */, D0F69E4F1D6B8BC40046BCD6 /* Gallery */, D0575AF81EA0FD94006F2541 /* Avatar Gallery */, + D0EEE99F2165583B001292A6 /* Document */, D0104F261F471702004E4881 /* Instant Page Gallery */, D0F69E671D6B8C030046BCD6 /* Map Input */, D07827CC1E03F32C00071108 /* Instant Page */, @@ -5210,6 +5221,7 @@ D06CF82920D0119500AC4CFF /* SecureIdAuthListFieldNode.swift in Sources */, D0EC6DCD1EB9F58900EBF1C3 /* ChatInputContextPanelNode.swift in Sources */, D0F8C399201774AF00236FC5 /* FeedGroupingControllerNode.swift in Sources */, + D0EEE9A12165585F001292A6 /* DocumentPreviewController.swift in Sources */, D0EC6DCE1EB9F58900EBF1C3 /* HorizontalStickersChatContextPanelNode.swift in Sources */, D0BCC3D2203F0A6C008126C2 /* StringForMessageTimestampStatus.swift in Sources */, D0EC6DCF1EB9F58900EBF1C3 /* HorizontalStickerGridItem.swift in Sources */, diff --git a/TelegramUI.xcodeproj/xcuserdata/peter.xcuserdatad/xcschemes/xcschememanagement.plist b/TelegramUI.xcodeproj/xcuserdata/peter.xcuserdatad/xcschemes/xcschememanagement.plist index 2545a615e8..4c544a1a8d 100644 --- a/TelegramUI.xcodeproj/xcuserdata/peter.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/TelegramUI.xcodeproj/xcuserdata/peter.xcuserdatad/xcschemes/xcschememanagement.plist @@ -7,7 +7,7 @@ TelegramUI.xcscheme orderHint - 3 + 2 SuppressBuildableAutocreation diff --git a/TelegramUI/BotCheckoutControllerNode.swift b/TelegramUI/BotCheckoutControllerNode.swift index d56ec06c33..eb4cd11f33 100644 --- a/TelegramUI/BotCheckoutControllerNode.swift +++ b/TelegramUI/BotCheckoutControllerNode.swift @@ -315,7 +315,8 @@ private let hasApplePaySupport: Bool = PKPaymentAuthorizationViewController.canM private var applePayProviders = Set([ "stripe", "sberbank", - "yandex" + "yandex", + "privatbank" ]) private func availablePaymentMethods(current: BotCheckoutPaymentMethod?, supportsApplePay: Bool) -> [BotCheckoutPaymentMethod] { diff --git a/TelegramUI/ChatController.swift b/TelegramUI/ChatController.swift index a6b8d92d5f..2e323b6d08 100644 --- a/TelegramUI/ChatController.swift +++ b/TelegramUI/ChatController.swift @@ -2647,27 +2647,29 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin self.interfaceInteraction = interfaceInteraction self.chatDisplayNode.interfaceInteraction = interfaceInteraction - self.galleryHiddenMesageAndMediaDisposable.set(self.account.telegramApplicationContext.mediaManager.galleryHiddenMediaManager.hiddenIds().start(next: { [weak self] ids in - if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction { - var messageIdAndMedia: [MessageId: [Media]] = [:] - - for id in ids { - if case let .chat(messageId, media) = id { - messageIdAndMedia[messageId] = [media] - } - } - - //if controllerInteraction.hiddenMedia != messageIdAndMedia { - controllerInteraction.hiddenMedia = messageIdAndMedia + if let mediaManager = self.account.telegramApplicationContext.mediaManager { + self.galleryHiddenMesageAndMediaDisposable.set(mediaManager.galleryHiddenMediaManager.hiddenIds().start(next: { [weak self] ids in + if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction { + var messageIdAndMedia: [MessageId: [Media]] = [:] - strongSelf.chatDisplayNode.historyNode.forEachItemNode { itemNode in - if let itemNode = itemNode as? ChatMessageItemView { - itemNode.updateHiddenMedia() + for id in ids { + if case let .chat(messageId, media) = id { + messageIdAndMedia[messageId] = [media] } } - //} - } - })) + + //if controllerInteraction.hiddenMedia != messageIdAndMedia { + controllerInteraction.hiddenMedia = messageIdAndMedia + + strongSelf.chatDisplayNode.historyNode.forEachItemNode { itemNode in + if let itemNode = itemNode as? ChatMessageItemView { + itemNode.updateHiddenMedia() + } + } + //} + } + })) + } self.chatDisplayNode.dismissAsOverlay = { [weak self] in if let strongSelf = self { @@ -3692,8 +3694,11 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin self.audioRecorderFeedback = HapticFeedback() self.audioRecorderFeedback?.prepareTap() } - self.audioRecorder.set(applicationContext.mediaManager.audioRecorder(beginWithTone: beginWithTone, applicationBindings: applicationContext.applicationBindings, beganWithTone: { _ in - })) + + if let mediaManager = applicationContext.mediaManager { + self.audioRecorder.set(mediaManager.audioRecorder(beginWithTone: beginWithTone, applicationBindings: applicationContext.applicationBindings, beganWithTone: { _ in + })) + } } } } diff --git a/TelegramUI/ChatItemGalleryFooterContentNode.swift b/TelegramUI/ChatItemGalleryFooterContentNode.swift index 70e200cc0c..2e4166d627 100644 --- a/TelegramUI/ChatItemGalleryFooterContentNode.swift +++ b/TelegramUI/ChatItemGalleryFooterContentNode.swift @@ -72,7 +72,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode { private let deleteButton: UIButton private let actionButton: UIButton - private let textNode: ASTextNode + private let textNode: ImmediateTextNode private let authorNameNode: ASTextNode private let dateNode: ASTextNode private let backwardButton: HighlightableButtonNode @@ -138,7 +138,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode { self.deleteButton.setImage(deleteImage, for: [.normal]) self.actionButton.setImage(actionImage, for: [.normal]) - self.textNode = ASTextNode() + self.textNode = ImmediateTextNode() + self.textNode.maximumNumberOfLines = 10 self.textNode.isLayerBacked = true self.authorNameNode = ASTextNode() self.authorNameNode.maximumNumberOfLines = 1 @@ -295,7 +296,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode { let sideInset: CGFloat = 8.0 + leftInset let topInset: CGFloat = 8.0 let textBottomInset: CGFloat = 8.0 - let textSize = self.textNode.measure(CGSize(width: width - sideInset * 2.0, height: CGFloat.greatestFiniteMagnitude)) + let textSize = self.textNode.updateLayout(CGSize(width: width - sideInset * 2.0, height: CGFloat.greatestFiniteMagnitude)) panelHeight += textSize.height + topInset + textBottomInset textFrame = CGRect(origin: CGPoint(x: sideInset, y: topInset), size: textSize) } diff --git a/TelegramUI/ChatMessageAttachedContentNode.swift b/TelegramUI/ChatMessageAttachedContentNode.swift index 2d3fab4be0..3d3d5c0555 100644 --- a/TelegramUI/ChatMessageAttachedContentNode.swift +++ b/TelegramUI/ChatMessageAttachedContentNode.swift @@ -328,7 +328,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { var inlineImageDimensions: CGSize? var inlineImageSize: CGSize? var updateInlineImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>? - var textCutout: TextNodeCutout? + var textCutout = TextNodeCutout() var initialWidth: CGFloat = CGFloat.greatestFiniteMagnitude var refineContentImageLayout: ((CGSize, ImageCorners) -> (CGFloat, (CGFloat) -> (CGSize, (ContainedViewLayoutTransition) -> ChatMessageInteractiveMediaNode)))? var refineContentFileLayout: ((CGSize) -> (CGFloat, (CGFloat) -> (CGSize, () -> ChatMessageInteractiveFileNode)))? @@ -435,7 +435,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { inlineImageSize = CGSize(width: 54.0, height: 54.0) if let inlineImageSize = inlineImageSize { - textCutout = TextNodeCutout(position: .TopRight, size: CGSize(width: inlineImageSize.width + 10.0, height: inlineImageSize.height + 10.0)) + textCutout.topRight = CGSize(width: inlineImageSize.width + 10.0, height: inlineImageSize.height + 10.0) } } @@ -508,23 +508,28 @@ final class ChatMessageAttachedContentNode: ASDisplayNode { updatedAdditionalImageBadge = currentAdditionalImageBadgeNode ?? ChatMessageInteractiveMediaBadge() } - let (textLayout, textApply) = textAsyncLayout(TextNodeLayoutArguments(attributedString: textString, backgroundColor: nil, maximumNumberOfLines: 12, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: textCutout, insets: UIEdgeInsets())) + var upatedTextCutout = textCutout + if statusInText, let (statusSize, _) = statusSizeAndApply { + upatedTextCutout.bottomRight = statusSize + } + + let (textLayout, textApply) = textAsyncLayout(TextNodeLayoutArguments(attributedString: textString, backgroundColor: nil, maximumNumberOfLines: 12, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: upatedTextCutout, insets: UIEdgeInsets())) var textFrame = CGRect(origin: CGPoint(), size: textLayout.size) var statusFrame: CGRect? if statusInText, let (statusSize, _) = statusSizeAndApply { - var frame = CGRect(origin: CGPoint(), size: statusSize) + var frame = CGRect(origin: CGPoint(x: textFrame.maxX - statusSize.width, y: textFrame.maxY - statusSize.height), size: statusSize) - let trailingLineWidth = textLayout.trailingLineWidth + /*let trailingLineWidth = textLayout.trailingLineWidth if textLayout.size.width - trailingLineWidth >= statusSize.width { frame.origin = CGPoint(x: textFrame.maxX - statusSize.width, y: textFrame.maxY - statusSize.height) } else if trailingLineWidth + statusSize.width < textConstrainedSize.width { frame.origin = CGPoint(x: textFrame.minX + trailingLineWidth, y: textFrame.maxY - statusSize.height) } else { frame.origin = CGPoint(x: textFrame.maxX - statusSize.width, y: textFrame.maxY) - } + }*/ if let inlineImageSize = inlineImageSize { if frame.origin.y < inlineImageSize.height + 4.0 { diff --git a/TelegramUI/ChatMessageInteractiveFileNode.swift b/TelegramUI/ChatMessageInteractiveFileNode.swift index 69f2d874f0..19502b0d65 100644 --- a/TelegramUI/ChatMessageInteractiveFileNode.swift +++ b/TelegramUI/ChatMessageInteractiveFileNode.swift @@ -101,7 +101,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode { } case .playbackStatus: if let account = self.account, let applicationContext = account.applicationContext as? TelegramApplicationContext, let message = self.message, let type = peerMessageMediaPlayerType(message) { - applicationContext.mediaManager.playlistControl(.playback(.togglePlayPause), type: type) + applicationContext.mediaManager?.playlistControl(.playback(.togglePlayPause), type: type) } } } @@ -418,7 +418,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode { waveformScrubbingNode.hitTestSlop = UIEdgeInsetsMake(-10.0, 0.0, -10.0, 0.0) waveformScrubbingNode.seek = { timestamp in if let strongSelf = self, let account = strongSelf.account, let message = strongSelf.message, let type = peerMessageMediaPlayerType(message) { - account.telegramApplicationContext.mediaManager.playlistControl(.seek(timestamp), type: type) + account.telegramApplicationContext.mediaManager?.playlistControl(.seek(timestamp), type: type) } } waveformScrubbingNode.status = strongSelf.playbackStatus.get() diff --git a/TelegramUI/ChatMessageInteractiveInstantVideoNode.swift b/TelegramUI/ChatMessageInteractiveInstantVideoNode.swift index 1d8491b638..20bdf2226c 100644 --- a/TelegramUI/ChatMessageInteractiveInstantVideoNode.swift +++ b/TelegramUI/ChatMessageInteractiveInstantVideoNode.swift @@ -328,28 +328,30 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { videoNode?.removeFromSupernode() }) } - let videoNode = UniversalVideoNode(postbox: item.account.postbox, audioSession: item.account.telegramApplicationContext.mediaManager.audioSession, manager: item.account.telegramApplicationContext.mediaManager.universalVideoManager, decoration: ChatBubbleInstantVideoDecoration(diameter: displaySize.width + 2.0, backgroundImage: instantVideoBackgroundImage, tapped: { - if let strongSelf = self { - if let item = strongSelf.item { - if strongSelf.infoBackgroundNode.alpha.isZero { - item.account.telegramApplicationContext.mediaManager.playlistControl(.playback(.togglePlayPause), type: .voice) - } else { - //let _ = item.controllerInteraction.openMessage(item.message) + if let mediaManager = item.account.telegramApplicationContext.mediaManager { + let videoNode = UniversalVideoNode(postbox: item.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: ChatBubbleInstantVideoDecoration(diameter: displaySize.width + 2.0, backgroundImage: instantVideoBackgroundImage, tapped: { + if let strongSelf = self { + if let item = strongSelf.item { + if strongSelf.infoBackgroundNode.alpha.isZero { + item.account.telegramApplicationContext.mediaManager?.playlistControl(.playback(.togglePlayPause), type: .voice) + } else { + //let _ = item.controllerInteraction.openMessage(item.message) + } } } - } - }), content: NativeVideoContent(id: .message(item.message.id, item.message.stableId, telegramFile.fileId), fileReference: .message(message: MessageReference(item.message), media: telegramFile), streamVideo: false, enableSound: false), priority: .embedded, autoplay: true) - let previousVideoNode = strongSelf.videoNode - strongSelf.videoNode = videoNode - strongSelf.insertSubnode(videoNode, belowSubnode: previousVideoNode ?? strongSelf.dateAndStatusNode) - videoNode.canAttachContent = strongSelf.shouldAcquireVideoContext + }), content: NativeVideoContent(id: .message(item.message.id, item.message.stableId, telegramFile.fileId), fileReference: .message(message: MessageReference(item.message), media: telegramFile), streamVideo: false, enableSound: false), priority: .embedded, autoplay: true) + let previousVideoNode = strongSelf.videoNode + strongSelf.videoNode = videoNode + strongSelf.insertSubnode(videoNode, belowSubnode: previousVideoNode ?? strongSelf.dateAndStatusNode) + videoNode.canAttachContent = strongSelf.shouldAcquireVideoContext - if isSecretMedia { - let updatedSecretPlaceholderSignal = chatSecretMessageVideo(account: item.account, videoReference: .message(message: MessageReference(item.message), media: telegramFile)) - strongSelf.secretVideoPlaceholder.setSignal(updatedSecretPlaceholderSignal) - if strongSelf.secretVideoPlaceholder.supernode == nil { - strongSelf.insertSubnode(strongSelf.secretVideoPlaceholderBackground, belowSubnode: videoNode) - strongSelf.insertSubnode(strongSelf.secretVideoPlaceholder, belowSubnode: videoNode) + if isSecretMedia { + let updatedSecretPlaceholderSignal = chatSecretMessageVideo(account: item.account, videoReference: .message(message: MessageReference(item.message), media: telegramFile)) + strongSelf.secretVideoPlaceholder.setSignal(updatedSecretPlaceholderSignal) + if strongSelf.secretVideoPlaceholder.supernode == nil { + strongSelf.insertSubnode(strongSelf.secretVideoPlaceholderBackground, belowSubnode: videoNode) + strongSelf.insertSubnode(strongSelf.secretVideoPlaceholder, belowSubnode: videoNode) + } } } else { strongSelf.secretVideoPlaceholder.removeFromSupernode() @@ -548,7 +550,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { return } - if let item = self.item, let videoNode = self.videoNode, videoNode.frame.contains(location) { + if let _ = self.item, let videoNode = self.videoNode, videoNode.frame.contains(location) { self.activateVideoPlayback() return } @@ -572,7 +574,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { return } if self.infoBackgroundNode.alpha.isZero { - item.account.telegramApplicationContext.mediaManager.playlistControl(.playback(.togglePlayPause), type: .voice) + item.account.telegramApplicationContext.mediaManager?.playlistControl(.playback(.togglePlayPause), type: .voice) } else { let _ = item.controllerInteraction.openMessage(item.message) } diff --git a/TelegramUI/ChatMessageInteractiveMediaNode.swift b/TelegramUI/ChatMessageInteractiveMediaNode.swift index 32ee064938..3b60f40094 100644 --- a/TelegramUI/ChatMessageInteractiveMediaNode.swift +++ b/TelegramUI/ChatMessageInteractiveMediaNode.swift @@ -384,9 +384,9 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode { strongSelf.videoNode = nil } - if replaceVideoNode, let updatedVideoFile = updateVideoFile { + if replaceVideoNode, let updatedVideoFile = updateVideoFile, let mediaManager = account.telegramApplicationContext.mediaManager { let cornerRadius: CGFloat = arguments.corners.topLeft.radius - let videoNode = UniversalVideoNode(postbox: account.postbox, audioSession: account.telegramApplicationContext.mediaManager.audioSession, manager: account.telegramApplicationContext.mediaManager.universalVideoManager, decoration: ChatBubbleVideoDecoration(cornerRadius: cornerRadius, nativeSize: nativeSize), content: NativeVideoContent(id: .message(message.id, message.stableId, updatedVideoFile.fileId), fileReference: .message(message: MessageReference(message), media: updatedVideoFile), enableSound: false, fetchAutomatically: false), priority: .embedded) + let videoNode = UniversalVideoNode(postbox: account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: ChatBubbleVideoDecoration(cornerRadius: cornerRadius, nativeSize: nativeSize), content: NativeVideoContent(id: .message(message.id, message.stableId, updatedVideoFile.fileId), fileReference: .message(message: MessageReference(message), media: updatedVideoFile), enableSound: false, fetchAutomatically: false), priority: .embedded) videoNode.isUserInteractionEnabled = false strongSelf.videoNode = videoNode diff --git a/TelegramUI/ChatMessageTextBubbleContentNode.swift b/TelegramUI/ChatMessageTextBubbleContentNode.swift index 206108ac7a..be65c30bf0 100644 --- a/TelegramUI/ChatMessageTextBubbleContentNode.swift +++ b/TelegramUI/ChatMessageTextBubbleContentNode.swift @@ -168,7 +168,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { var cutout: TextNodeCutout? if let statusSize = statusSize { - cutout = TextNodeCutout(position: .BottomRight, size: statusSize) + cutout = TextNodeCutout(bottomRight: statusSize) } let (textLayout, textApply) = textLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: cutout, insets: UIEdgeInsets())) @@ -178,16 +178,14 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { var statusFrame: CGRect? if let statusSize = statusSize { - var frame = CGRect(origin: CGPoint(), size: statusSize) + var frame = CGRect(origin: CGPoint(x: textFrame.maxX - statusSize.width, y: textFrame.maxY - statusSize.height), size: statusSize) - let trailingLineWidth = textLayout.trailingLineWidth + /*let trailingLineWidth = textLayout.trailingLineWidth if textSize.width - trailingLineWidth >= statusSize.width { frame.origin = CGPoint(x: textFrame.maxX - statusSize.width, y: textFrame.maxY - statusSize.height) } else if trailingLineWidth + statusSize.width < textConstrainedSize.width { frame.origin = CGPoint(x: textFrame.minX + trailingLineWidth, y: textFrame.maxY - statusSize.height) - } else { - frame.origin = CGPoint(x: textFrame.maxX - statusSize.width, y: textFrame.maxY) - } + }*/ statusFrame = frame } diff --git a/TelegramUI/ChatRecentActionsControllerNode.swift b/TelegramUI/ChatRecentActionsControllerNode.swift index 41c89f2c27..f75742f921 100644 --- a/TelegramUI/ChatRecentActionsControllerNode.swift +++ b/TelegramUI/ChatRecentActionsControllerNode.swift @@ -397,27 +397,30 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { self.historyDisposable = appliedTransition.start() - self.galleryHiddenMesageAndMediaDisposable.set(self.account.telegramApplicationContext.mediaManager.galleryHiddenMediaManager.hiddenIds().start(next: { [weak self] ids in - if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction { - var messageIdAndMedia: [MessageId: [Media]] = [:] - - for id in ids { - if case let .chat(messageId, media) = id { - messageIdAndMedia[messageId] = [media] + + if let mediaManager = self.account.telegramApplicationContext.mediaManager { + self.galleryHiddenMesageAndMediaDisposable.set(mediaManager.galleryHiddenMediaManager.hiddenIds().start(next: { [weak self] ids in + if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction { + var messageIdAndMedia: [MessageId: [Media]] = [:] + + for id in ids { + if case let .chat(messageId, media) = id { + messageIdAndMedia[messageId] = [media] + } } - } - - //if controllerInteraction.hiddenMedia != messageIdAndMedia { - controllerInteraction.hiddenMedia = messageIdAndMedia - - strongSelf.listNode.forEachItemNode { itemNode in - if let itemNode = itemNode as? ChatMessageItemView { - itemNode.updateHiddenMedia() + + //if controllerInteraction.hiddenMedia != messageIdAndMedia { + controllerInteraction.hiddenMedia = messageIdAndMedia + + strongSelf.listNode.forEachItemNode { itemNode in + if let itemNode = itemNode as? ChatMessageItemView { + itemNode.updateHiddenMedia() + } } + //} } - //} - } - })) + })) + } } deinit { diff --git a/TelegramUI/ChatRecordingPreviewInputPanelNode.swift b/TelegramUI/ChatRecordingPreviewInputPanelNode.swift index 71df1f726b..5fd2fa9635 100644 --- a/TelegramUI/ChatRecordingPreviewInputPanelNode.swift +++ b/TelegramUI/ChatRecordingPreviewInputPanelNode.swift @@ -109,8 +109,8 @@ final class ChatRecordingPreviewInputPanelNode: ChatInputPanelNode { if self.mediaPlayer != nil { self.mediaPlayer?.pause() } - if let account = self.account { - let mediaPlayer = MediaPlayer(audioSessionManager: account.telegramApplicationContext.mediaManager.audioSession, postbox: account.postbox, resourceReference: .standalone(resource: recordedMediaPreview.resource), streamable: false, video: false, preferSoftwareDecoding: false, enableSound: true, fetchAutomatically: true) + if let account = self.account, let mediaManager = account.telegramApplicationContext.mediaManager { + let mediaPlayer = MediaPlayer(audioSessionManager: mediaManager.audioSession, postbox: account.postbox, resourceReference: .standalone(resource: recordedMediaPreview.resource), streamable: false, video: false, preferSoftwareDecoding: false, enableSound: true, fetchAutomatically: true) self.mediaPlayer = mediaPlayer self.durationLabel.defaultDuration = Double(recordedMediaPreview.duration) self.durationLabel.status = mediaPlayer.status diff --git a/TelegramUI/ChatRequestInProgressTitlePanelNode.swift b/TelegramUI/ChatRequestInProgressTitlePanelNode.swift index 374e9451ab..836d122ea9 100644 --- a/TelegramUI/ChatRequestInProgressTitlePanelNode.swift +++ b/TelegramUI/ChatRequestInProgressTitlePanelNode.swift @@ -4,7 +4,7 @@ import AsyncDisplayKit final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode { private let separatorNode: ASDisplayNode - private let titleNode: ASTextNode + private let titleNode: ImmediateTextNode private var theme: PresentationTheme? private var strings: PresentationStrings? @@ -13,7 +13,7 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode { self.separatorNode = ASDisplayNode() self.separatorNode.isLayerBacked = true - self.titleNode = ASTextNode() + self.titleNode = ImmediateTextNode() self.titleNode.maximumNumberOfLines = 1 super.init() @@ -38,7 +38,7 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode { let panelHeight: CGFloat = 40.0 - let titleSize = self.titleNode.measure(CGSize(width: width - leftInset - rightInset, height: 100.0)) + let titleSize = self.titleNode.updateLayout(CGSize(width: width - leftInset - rightInset, height: 100.0)) transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: floor((panelHeight - titleSize.height) / 2.0)), size: titleSize)) transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel))) diff --git a/TelegramUI/ChatTitleView.swift b/TelegramUI/ChatTitleView.swift index 1472e7c61a..c6ac3b82e8 100644 --- a/TelegramUI/ChatTitleView.swift +++ b/TelegramUI/ChatTitleView.swift @@ -14,7 +14,7 @@ enum ChatTitleContent { private final class ChatTitleNetworkStatusNode: ASDisplayNode { private var theme: PresentationTheme - private let titleNode: ASTextNode + private let titleNode: ImmediateTextNode private let activityIndicator: ActivityIndicator var title: String = "" { @@ -28,11 +28,10 @@ private final class ChatTitleNetworkStatusNode: ASDisplayNode { init(theme: PresentationTheme) { self.theme = theme - self.titleNode = ASTextNode() + self.titleNode = ImmediateTextNode() self.titleNode.isLayerBacked = true self.titleNode.displaysAsynchronously = false self.titleNode.maximumNumberOfLines = 1 - self.titleNode.truncationMode = .byTruncatingTail self.titleNode.isOpaque = false self.titleNode.isUserInteractionEnabled = false @@ -57,7 +56,7 @@ private final class ChatTitleNetworkStatusNode: ASDisplayNode { let indicatorSize = self.activityIndicator.bounds.size let indicatorPadding = indicatorSize.width + 6.0 - let titleSize = self.titleNode.measure(CGSize(width: max(1.0, size.width - indicatorPadding), height: size.height)) + let titleSize = self.titleNode.updateLayout(CGSize(width: max(1.0, size.width - indicatorPadding), height: size.height)) let combinedHeight = titleSize.height let titleFrame = CGRect(origin: CGPoint(x: indicatorPadding + floor((size.width - titleSize.width - indicatorPadding) / 2.0), y: floor((size.height - combinedHeight) / 2.0)), size: titleSize) @@ -81,11 +80,11 @@ final class ChatTitleView: UIView, NavigationBarTitleView { private var dateTimeFormat: PresentationDateTimeFormat private let contentContainer: ASDisplayNode - private let titleNode: ASTextNode + private let titleNode: ImmediateTextNode private let titleLeftIconNode: ASImageNode private let titleRightIconNode: ASImageNode - private let infoNode: ASTextNode - private let typingNode: ASTextNode + private let infoNode: ImmediateTextNode + private let typingNode: ImmediateTextNode private var typingIndicator: TGModernConversationTitleActivityIndicator? private let button: HighlightTrackingButtonNode @@ -428,10 +427,9 @@ final class ChatTitleView: UIView, NavigationBarTitleView { self.contentContainer = ASDisplayNode() - self.titleNode = ASTextNode() + self.titleNode = ImmediateTextNode() self.titleNode.displaysAsynchronously = false self.titleNode.maximumNumberOfLines = 1 - self.titleNode.truncationMode = .byTruncatingTail self.titleNode.isOpaque = false self.titleLeftIconNode = ASImageNode() @@ -444,16 +442,14 @@ final class ChatTitleView: UIView, NavigationBarTitleView { self.titleRightIconNode.displayWithoutProcessing = true self.titleRightIconNode.displaysAsynchronously = false - self.infoNode = ASTextNode() + self.infoNode = ImmediateTextNode() self.infoNode.displaysAsynchronously = false self.infoNode.maximumNumberOfLines = 1 - self.infoNode.truncationMode = .byTruncatingTail self.infoNode.isOpaque = false - self.typingNode = ASTextNode() + self.typingNode = ImmediateTextNode() self.typingNode.displaysAsynchronously = false self.typingNode.maximumNumberOfLines = 1 - self.typingNode.truncationMode = .byTruncatingTail self.typingNode.isOpaque = false self.button = HighlightTrackingButtonNode() @@ -548,9 +544,9 @@ final class ChatTitleView: UIView, NavigationBarTitleView { } if size.height > 40.0 { - let titleSize = self.titleNode.measure(CGSize(width: clearBounds.width - leftIconWidth - rightIconWidth, height: size.height)) - let infoSize = self.infoNode.measure(clearBounds.size) - let typingSize = self.typingNode.measure(clearBounds.size) + let titleSize = self.titleNode.updateLayout(CGSize(width: clearBounds.width - leftIconWidth - rightIconWidth, height: size.height)) + let infoSize = self.infoNode.updateLayout(clearBounds.size) + let typingSize = self.typingNode.updateLayout(clearBounds.size) let titleInfoSpacing: CGFloat = 0.0 var titleFrame: CGRect @@ -590,9 +586,9 @@ final class ChatTitleView: UIView, NavigationBarTitleView { self.titleRightIconNode.frame = CGRect(origin: CGPoint(x: titleFrame.maxX + 3.0, y: titleFrame.minY + 7.0), size: image.size) } } else { - let titleSize = self.titleNode.measure(CGSize(width: floor(clearBounds.width / 2.0 - leftIconWidth - rightIconWidth), height: size.height)) - let infoSize = self.infoNode.measure(CGSize(width: floor(clearBounds.width / 2.0), height: size.height)) - let typingSize = self.typingNode.measure(CGSize(width: floor(clearBounds.width / 2.0), height: size.height)) + let titleSize = self.titleNode.updateLayout(CGSize(width: floor(clearBounds.width / 2.0 - leftIconWidth - rightIconWidth), height: size.height)) + let infoSize = self.infoNode.updateLayout(CGSize(width: floor(clearBounds.width / 2.0), height: size.height)) + let typingSize = self.typingNode.updateLayout(CGSize(width: floor(clearBounds.width / 2.0), height: size.height)) let titleInfoSpacing: CGFloat = 8.0 let combinedWidth = titleSize.width + leftIconWidth + rightIconWidth + infoSize.width + titleInfoSpacing diff --git a/TelegramUI/DeviceContactDataManager.swift b/TelegramUI/DeviceContactDataManager.swift index e42ae778b9..f788be9deb 100644 --- a/TelegramUI/DeviceContactDataManager.swift +++ b/TelegramUI/DeviceContactDataManager.swift @@ -222,6 +222,142 @@ private final class DeviceContactDataModernContext: DeviceContactDataContext { } } +private func withAddressBook(_ f: (ABAddressBook) -> Void) { + let addressBookRef = ABAddressBookCreateWithOptions(nil, nil) + + if let addressBook = addressBookRef?.takeRetainedValue() { + f(addressBook) + } +} + +private final class DeviceContactDataLegacyContext: DeviceContactDataContext { + var currentContacts: [DeviceContactStableId: DeviceContactBasicData] = [:] + + init(queue: Queue, updated: @escaping ([DeviceContactStableId: DeviceContactBasicData]) -> Void) { + self.currentContacts = self.retrieveContacts() + updated(self.currentContacts) + /*let handle = NotificationCenter.default.addObserver(forName: NSNotification.Name.CNContactStoreDidChange, object: nil, queue: nil, using: { [weak self] _ in + queue.async { + guard let strongSelf = self else { + return + } + let contacts = strongSelf.retrieveContacts() + if strongSelf.currentContacts != contacts { + strongSelf.currentContacts = contacts + updated(strongSelf.currentContacts) + } + } + })*/ + //self.updateHandle = handle + } + + deinit { + /*if let updateHandle = updateHandle { + NotificationCenter.default.removeObserver(updateHandle) + }*/ + } + + private func retrieveContacts() -> [DeviceContactStableId: DeviceContactBasicData] { + var result: [DeviceContactStableId: DeviceContactBasicData] = [:] + withAddressBook { addressBook in + guard let peopleRef = ABAddressBookCopyArrayOfAllPeople(addressBook)?.takeRetainedValue() else { + return + } + + for recordRef in peopleRef as NSArray { + let record = recordRef as ABRecord + let (stableId, basicData) = DeviceContactDataLegacyContext.parseContact(record) + result[stableId] = basicData + } + } + return result + } + + private func getContactById(stableId: String) -> ABRecord? { + let recordId: ABRecordID + if stableId.hasPrefix("ab-"), let idValue = Int(String(stableId[stableId.index(stableId.startIndex, offsetBy: 3)])) { + recordId = Int32(clamping: idValue) + } else { + return nil + } + + var result: ABRecord? + withAddressBook { addressBook in + result = ABAddressBookGetPersonWithRecordID(addressBook, recordId)?.takeUnretainedValue() + } + return result + } + + private static func parseContact(_ contact: ABRecord) -> (DeviceContactStableId, DeviceContactBasicData) { + let stableId = "ab-\(ABRecordGetRecordID(contact))" + var firstName = "" + var lastName = "" + if let value = ABRecordCopyValue(contact, kABPersonFirstNameProperty)?.takeRetainedValue() { + firstName = value as! CFString as String + } + if let value = ABRecordCopyValue(contact, kABPersonLastNameProperty)?.takeRetainedValue() { + lastName = value as! CFString as String + } + + var phoneNumbers: [DeviceContactPhoneNumberData] = [] + if let value = ABRecordCopyValue(contact, kABPersonPhoneProperty)?.takeRetainedValue() { + let phones = value as ABMultiValue + let count = ABMultiValueGetCount(phones) + for i in 0 ..< count { + if let phoneRef = ABMultiValueCopyValueAtIndex(phones, i)?.takeRetainedValue() { + let phone = phoneRef as! CFString as String + var label = "" + if let labelRef = ABMultiValueCopyLabelAtIndex(phones, i)?.takeRetainedValue() { + label = labelRef as String + } + phoneNumbers.append(DeviceContactPhoneNumberData(label: label, value: phone)) + } + } + } + + return (stableId, DeviceContactBasicData(firstName: firstName, lastName: lastName, phoneNumbers: phoneNumbers)) + } + + func getExtendedContactData(stableId: DeviceContactStableId) -> DeviceContactExtendedData? { + if let contact = self.getContactById(stableId: stableId) { + let basicData = DeviceContactDataLegacyContext.parseContact(contact).1 + return DeviceContactExtendedData(basicData: basicData, middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: []) + } else { + return nil + } + } + + func appendContactData(_ contactData: DeviceContactExtendedData, to stableId: DeviceContactStableId) -> DeviceContactExtendedData? { + return nil + } + + func createContactWithData(_ contactData: DeviceContactExtendedData) -> (DeviceContactStableId, DeviceContactExtendedData)? { + var result: (DeviceContactStableId, DeviceContactExtendedData)? + withAddressBook { addressBook in + let contact = ABPersonCreate()?.takeRetainedValue() + ABRecordSetValue(contact, kABPersonFirstNameProperty, contactData.basicData.firstName as CFString, nil) + ABRecordSetValue(contact, kABPersonLastNameProperty, contactData.basicData.lastName as CFString, nil) + + let phones = ABMultiValueCreateMutable(ABPropertyType(kABMultiStringPropertyType))?.takeRetainedValue() + for phone in contactData.basicData.phoneNumbers { + ABMultiValueAddValueAndLabel(phones, phone.value as CFString, phone.label as CFString, nil) + } + ABRecordSetValue(contact, kABPersonPhoneProperty, phones, nil) + + if ABAddressBookAddRecord(addressBook, contact, nil) { + ABAddressBookSave(addressBook, nil) + + let stableId = "ab-\(ABRecordGetRecordID(contact))" + if let contact = self.getContactById(stableId: stableId) { + let parsedContact = DeviceContactDataLegacyContext.parseContact(contact).1 + result = (stableId, DeviceContactExtendedData(basicData: parsedContact, middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [])) + } + } + } + return result + } +} + private final class ExtendedContactDataContext { var value: DeviceContactExtendedData? let subscribers = Bag<(DeviceContactExtendedData) -> Void>() @@ -273,8 +409,20 @@ private final class DeviceContactDataManagerImpl { strongSelf.updateAll(stableIdToBasicContactData) }) } else { - + strongSelf.dataContext = DeviceContactDataLegacyContext(queue: strongSelf.queue, updated: { stableIdToBasicContactData in + guard let strongSelf = self else { + return + } + strongSelf.updateAll(stableIdToBasicContactData) + }) } + + /*strongSelf.dataContext = DeviceContactDataLegacyContext(queue: strongSelf.queue, updated: { stableIdToBasicContactData in + guard let strongSelf = self else { + return + } + strongSelf.updateAll(stableIdToBasicContactData) + })*/ } else { strongSelf.updateAll([:]) } diff --git a/TelegramUI/DocumentPreviewController.swift b/TelegramUI/DocumentPreviewController.swift new file mode 100644 index 0000000000..4583a06b43 --- /dev/null +++ b/TelegramUI/DocumentPreviewController.swift @@ -0,0 +1,103 @@ +import Foundation +import UIKit +import SwiftSignalKit +import Postbox +import TelegramCore +import QuickLook +import Display + +private final class DocumentPreviewItem: NSObject, QLPreviewItem { + private let url: URL + private let title: String + + var previewItemURL: URL? { + return self.url + } + + var previewItemTitle: String? { + return self.title + } + + init(url: URL, title: String) { + self.url = url + self.title = title + } +} + +final class DocumentPreviewController: UINavigationController, QLPreviewControllerDelegate, QLPreviewControllerDataSource { + private let postbox: Postbox + private let file: TelegramMediaFile + + private var item: DocumentPreviewItem? + + init(theme: PresentationTheme, strings: PresentationStrings, postbox: Postbox, file: TelegramMediaFile) { + self.postbox = postbox + self.file = file + + super.init(nibName: nil, bundle: nil) + + self.navigationBar.barTintColor = theme.rootController.navigationBar.backgroundColor + self.navigationBar.tintColor = theme.rootController.navigationBar.accentTextColor + self.navigationBar.shadowImage = generateImage(CGSize(width: 1.0, height: 1.0), rotatedContext: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + context.setFillColor(theme.rootController.navigationBar.separatorColor.cgColor) + context.fill(CGRect(origin: CGPoint(), size: CGSize(width: 1.0, height: UIScreenPixel))) + }) + self.navigationBar.isTranslucent = false + self.navigationBar.titleTextAttributes = [NSAttributedStringKey.font: Font.semibold(17.0), NSAttributedStringKey.foregroundColor: theme.rootController.navigationBar.primaryTextColor] + + let controller = QLPreviewController(nibName: nil, bundle: nil) + controller.navigation_setDismiss({ [weak self] in + //self?.cancelPressed() + }, rootController: self) + controller.delegate = self + controller.dataSource = self + controller.navigationItem.setLeftBarButton(UIBarButtonItem(title: strings.Common_Cancel, style: .plain, target: self, action: #selector(self.cancelPressed)), animated: false) + self.setViewControllers([controller], animated: false) + + var pathExtension: String? + if let fileName = self.file.fileName { + let pathExtensionCandidate = (fileName as NSString).pathExtension + if !pathExtensionCandidate.isEmpty { + pathExtension = pathExtensionCandidate + } + } + + if let path = self.postbox.mediaBox.completedResourcePath(self.file.resource, pathExtension: pathExtension) { + self.item = DocumentPreviewItem(url: URL(fileURLWithPath: path), title: self.file.fileName ?? strings.Message_File) + } + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc private func cancelPressed() { + self.presentingViewController?.dismiss(animated: true, completion: nil) + } + + func numberOfPreviewItems(in controller: QLPreviewController) -> Int { + if self.item != nil { + return 1 + } else { + return 0 + } + } + + func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem { + if let item = self.item { + return item + } else { + assertionFailure() + return DocumentPreviewItem(url: URL(fileURLWithPath: ""), title: "") + } + } + + func previewControllerWillDismiss(_ controller: QLPreviewController) { + self.cancelPressed() + } + + func previewControllerDidDismiss(_ controller: QLPreviewController) { + //self.cancelPressed() + } +} diff --git a/TelegramUI/EditAccessoryPanelNode.swift b/TelegramUI/EditAccessoryPanelNode.swift index d8049af9e0..dce7f41ebc 100644 --- a/TelegramUI/EditAccessoryPanelNode.swift +++ b/TelegramUI/EditAccessoryPanelNode.swift @@ -10,8 +10,8 @@ final class EditAccessoryPanelNode: AccessoryPanelNode { let closeButton: ASButtonNode let lineNode: ASImageNode - let titleNode: ASTextNode - let textNode: ASTextNode + let titleNode: ImmediateTextNode + let textNode: ImmediateTextNode let imageNode: TransformImageNode private let activityIndicator: ActivityIndicator @@ -68,13 +68,11 @@ final class EditAccessoryPanelNode: AccessoryPanelNode { self.lineNode.displaysAsynchronously = false self.lineNode.image = PresentationResourcesChat.chatInputPanelVerticalSeparatorLineImage(theme) - self.titleNode = ASTextNode() - self.titleNode.truncationMode = .byTruncatingTail + self.titleNode = ImmediateTextNode() self.titleNode.maximumNumberOfLines = 1 self.titleNode.displaysAsynchronously = false - self.textNode = ASTextNode() - self.textNode.truncationMode = .byTruncatingTail + self.textNode = ImmediateTextNode() self.textNode.maximumNumberOfLines = 1 self.textNode.displaysAsynchronously = false self.textNode.isUserInteractionEnabled = true @@ -308,10 +306,10 @@ final class EditAccessoryPanelNode: AccessoryPanelNode { } self.imageNode.frame = CGRect(origin: CGPoint(x: leftInset + 9.0, y: 8.0), size: CGSize(width: 35.0, height: 35.0)) - let titleSize = self.titleNode.measure(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset - imageTextInset, height: bounds.size.height)) + let titleSize = self.titleNode.updateLayout(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset - imageTextInset, height: bounds.size.height)) self.titleNode.frame = CGRect(origin: CGPoint(x: leftInset + textLineInset + imageTextInset, y: 7.0), size: titleSize) - let textSize = self.textNode.measure(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset - imageTextInset, height: bounds.size.height)) + let textSize = self.textNode.updateLayout(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset - imageTextInset, height: bounds.size.height)) self.textNode.frame = CGRect(origin: CGPoint(x: leftInset + textLineInset + imageTextInset, y: 25.0), size: textSize) self.tapNode.frame = CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: bounds.width - leftInset - rightInset - closeButtonSize.width - 4.0, height: bounds.height)) diff --git a/TelegramUI/FileMediaResourceStatus.swift b/TelegramUI/FileMediaResourceStatus.swift index 23a4fa6955..8db73857a0 100644 --- a/TelegramUI/FileMediaResourceStatus.swift +++ b/TelegramUI/FileMediaResourceStatus.swift @@ -19,10 +19,14 @@ private func internalMessageFileMediaPlaybackStatus(account: Account, file: Tele } if let (playlistId, itemId) = peerMessagesMediaPlaylistAndItemId(message, isRecentActions: isRecentActions) { - return account.telegramApplicationContext.mediaManager.filteredPlaylistState(playlistId: playlistId, itemId: itemId, type: playerType) + if let mediaManager = account.telegramApplicationContext.mediaManager { + return mediaManager.filteredPlaylistState(playlistId: playlistId, itemId: itemId, type: playerType) |> mapToSignal { state -> Signal in return .single(state?.status) } + } else { + return .single(nil) + } } else { return .single(nil) } diff --git a/TelegramUI/ForwardAccessoryPanelNode.swift b/TelegramUI/ForwardAccessoryPanelNode.swift index 0c845fa08e..2354824720 100644 --- a/TelegramUI/ForwardAccessoryPanelNode.swift +++ b/TelegramUI/ForwardAccessoryPanelNode.swift @@ -64,8 +64,8 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode { let closeButton: ASButtonNode let lineNode: ASImageNode - let titleNode: ASTextNode - let textNode: ASTextNode + let titleNode: ImmediateTextNode + let textNode: ImmediateTextNode var theme: PresentationTheme @@ -83,13 +83,11 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode { self.lineNode.displaysAsynchronously = false self.lineNode.image = PresentationResourcesChat.chatInputPanelVerticalSeparatorLineImage(theme) - self.titleNode = ASTextNode() - self.titleNode.truncationMode = .byTruncatingTail + self.titleNode = ImmediateTextNode() self.titleNode.maximumNumberOfLines = 1 self.titleNode.displaysAsynchronously = false - self.textNode = ASTextNode() - self.textNode.truncationMode = .byTruncatingTail + self.textNode = ImmediateTextNode() self.textNode.maximumNumberOfLines = 1 self.textNode.displaysAsynchronously = false @@ -174,10 +172,10 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode { self.lineNode.frame = CGRect(origin: CGPoint(x: leftInset, y: 8.0), size: CGSize(width: 2.0, height: bounds.size.height - 10.0)) - let titleSize = self.titleNode.measure(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset, height: bounds.size.height)) + let titleSize = self.titleNode.updateLayout(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset, height: bounds.size.height)) self.titleNode.frame = CGRect(origin: CGPoint(x: leftInset + textLineInset, y: 7.0), size: titleSize) - let textSize = self.textNode.measure(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset, height: bounds.size.height)) + let textSize = self.textNode.updateLayout(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset, height: bounds.size.height)) self.textNode.frame = CGRect(origin: CGPoint(x: leftInset + textLineInset, y: 25.0), size: textSize) } diff --git a/TelegramUI/GalleryController.swift b/TelegramUI/GalleryController.swift index 72236bf9ed..34ff6d6ba6 100644 --- a/TelegramUI/GalleryController.swift +++ b/TelegramUI/GalleryController.swift @@ -72,26 +72,9 @@ private func mediaForMessage(message: Message) -> Media? { } private let internalExtensions = Set([ - "txt", - "doc", - "docx", - "xls", - "xlsx", - "ppt", - "pptx", - "php", - "cpp", - "h", - "swift", - "m", - "mm", - "java", "jpg", "png", - "jpeg", - "json", - "rs", - "cs" + "jpeg" ]) private let internalNotSupportedExtensions = Set([ @@ -99,17 +82,12 @@ private let internalNotSupportedExtensions = Set([ ]) private let internalMimeTypes = Set([ - "application/pdf", - "application/postscript", - "application/text" ]) private let internalMimePrefixes: [String] = [ "image/jpeg", "image/jpg", - "image/png", - "text/", - "application/vnd.ms-" + "image/png" ] private let supportedVideoMimeTypes = Set([ @@ -455,13 +433,15 @@ class GalleryController: ViewController { } })) - self.hiddenMediaManagerIndex = account.telegramApplicationContext.mediaManager.galleryHiddenMediaManager.addSource(self._hiddenMedia.get() |> map { messageIdAndMedia in - if let (messageId, media) = messageIdAndMedia { - return .chat(messageId, media) - } else { - return nil - } - }) + if let mediaManager = account.telegramApplicationContext.mediaManager { + self.hiddenMediaManagerIndex = mediaManager.galleryHiddenMediaManager.addSource(self._hiddenMedia.get() |> map { messageIdAndMedia in + if let (messageId, media) = messageIdAndMedia { + return .chat(messageId, media) + } else { + return nil + } + }) + } } required init(coder aDecoder: NSCoder) { @@ -471,8 +451,8 @@ class GalleryController: ViewController { deinit { self.disposable.dispose() self.centralItemAttributesDisposable.dispose() - if let hiddenMediaManagerIndex = self.hiddenMediaManagerIndex { - self.account.telegramApplicationContext.mediaManager.galleryHiddenMediaManager.removeSource(hiddenMediaManagerIndex) + if let hiddenMediaManagerIndex = self.hiddenMediaManagerIndex, let mediaManager = self.account.telegramApplicationContext.mediaManager { + mediaManager.galleryHiddenMediaManager.removeSource(hiddenMediaManagerIndex) } } diff --git a/TelegramUI/HorizontalListContextResultsChatInputPanelItem.swift b/TelegramUI/HorizontalListContextResultsChatInputPanelItem.swift index 955b9c4435..24f61a82ea 100644 --- a/TelegramUI/HorizontalListContextResultsChatInputPanelItem.swift +++ b/TelegramUI/HorizontalListContextResultsChatInputPanelItem.swift @@ -347,10 +347,6 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode } } } - - /*if let applicationContext = item.account.applicationContext as? TelegramApplicationContext { - strongSelf.videoNode.acquireContext(account: item.account, mediaManager: applicationContext.mediaManager, id: ChatContextResultManagedMediaId(result: item.result), resource: videoResource, priority: 1) - }*/ } } diff --git a/TelegramUI/InstantPageAudioNode.swift b/TelegramUI/InstantPageAudioNode.swift index 6fcb53466a..85e7eb46dc 100644 --- a/TelegramUI/InstantPageAudioNode.swift +++ b/TelegramUI/InstantPageAudioNode.swift @@ -130,7 +130,7 @@ final class InstantPageAudioNode: ASDisplayNode, InstantPageNode { self.scrubbingNode.seek = { [weak self] timestamp in if let strongSelf = self { if let _ = strongSelf.playbackState { - strongSelf.account.telegramApplicationContext.mediaManager.playlistControl(.seek(timestamp), type: strongSelf.playlistType) + strongSelf.account.telegramApplicationContext.mediaManager?.playlistControl(.seek(timestamp), type: strongSelf.playlistType) } } } @@ -174,12 +174,12 @@ final class InstantPageAudioNode: ASDisplayNode, InstantPageNode { } })*/ - self.scrubbingNode.status = account.telegramApplicationContext.mediaManager.filteredPlaylistState(playlistId: InstantPageMediaPlaylistId(webpageId: webPage.webpageId), itemId: InstantPageMediaPlaylistItemId(index: self.media.index), type: self.playlistType) + self.scrubbingNode.status = account.telegramApplicationContext.mediaManager!.filteredPlaylistState(playlistId: InstantPageMediaPlaylistId(webpageId: webPage.webpageId), itemId: InstantPageMediaPlaylistItemId(index: self.media.index), type: self.playlistType) |> map { playbackState -> MediaPlayerStatus in return playbackState?.status ?? MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .paused) } - self.playerStatusDisposable = (account.telegramApplicationContext.mediaManager.filteredPlaylistState(playlistId: InstantPageMediaPlaylistId(webpageId: webPage.webpageId), itemId: InstantPageMediaPlaylistItemId(index: self.media.index), type: playlistType) + self.playerStatusDisposable = (account.telegramApplicationContext.mediaManager!.filteredPlaylistState(playlistId: InstantPageMediaPlaylistId(webpageId: webPage.webpageId), itemId: InstantPageMediaPlaylistItemId(index: self.media.index), type: playlistType) |> deliverOnMainQueue).start(next: { [weak self] playbackState in guard let strongSelf = self else { return @@ -246,7 +246,7 @@ final class InstantPageAudioNode: ASDisplayNode, InstantPageNode { @objc func buttonPressed() { if let _ = self.playbackState { - self.account.telegramApplicationContext.mediaManager.playlistControl(.playback(.togglePlayPause), type: self.playlistType) + self.account.telegramApplicationContext.mediaManager?.playlistControl(.playback(.togglePlayPause), type: self.playlistType) } else { self.openMedia(self.media) } diff --git a/TelegramUI/InstantPageControllerNode.swift b/TelegramUI/InstantPageControllerNode.swift index 06383e87a4..4e3b17f95b 100644 --- a/TelegramUI/InstantPageControllerNode.swift +++ b/TelegramUI/InstantPageControllerNode.swift @@ -783,7 +783,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { } } } - self.account.telegramApplicationContext.mediaManager.setPlaylist(InstantPageMediaPlaylist(webPage: webPage, items: medias, initialItemIndex: initialIndex), type: file.isVoice ? .voice : .music) + self.account.telegramApplicationContext.mediaManager?.setPlaylist(InstantPageMediaPlaylist(webPage: webPage, items: medias, initialItemIndex: initialIndex), type: file.isVoice ? .voice : .music) return } diff --git a/TelegramUI/InstantPagePlayableVideoNode.swift b/TelegramUI/InstantPagePlayableVideoNode.swift index b67a13544c..276aa89725 100644 --- a/TelegramUI/InstantPagePlayableVideoNode.swift +++ b/TelegramUI/InstantPagePlayableVideoNode.swift @@ -25,7 +25,7 @@ final class InstantPagePlayableVideoNode: ASDisplayNode, InstantPageNode { self.interactive = interactive self.openMedia = openMedia - self.videoNode = UniversalVideoNode(postbox: account.postbox, audioSession: account.telegramApplicationContext.mediaManager.audioSession, manager: account.telegramApplicationContext.mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: NativeVideoContent(id: .instantPage(webPage.webpageId, media.media.id!), fileReference: .webPage(webPage: WebpageReference(webPage), media: media.media as! TelegramMediaFile), loopVideo: true, enableSound: false, fetchAutomatically: true), priority: .embedded, autoplay: true) + self.videoNode = UniversalVideoNode(postbox: account.postbox, audioSession: account.telegramApplicationContext.mediaManager!.audioSession, manager: account.telegramApplicationContext.mediaManager!.universalVideoManager, decoration: GalleryVideoDecoration(), content: NativeVideoContent(id: .instantPage(webPage.webpageId, media.media.id!), fileReference: .webPage(webPage: WebpageReference(webPage), media: media.media as! TelegramMediaFile), loopVideo: true, enableSound: false, fetchAutomatically: true), priority: .embedded, autoplay: true) super.init() diff --git a/TelegramUI/ItemListActivityTextItem.swift b/TelegramUI/ItemListActivityTextItem.swift index fef3bcd9a9..f2d5810986 100644 --- a/TelegramUI/ItemListActivityTextItem.swift +++ b/TelegramUI/ItemListActivityTextItem.swift @@ -96,7 +96,7 @@ class ItemListActivityTextItemNode: ListViewItemNode { titleString.addAttributes([NSAttributedStringKey.font: titleFont], range: NSMakeRange(0, titleString.length)) } - let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleString, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - 20.0 - 22.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: TextNodeCutout(position: .TopLeft, size: CGSize(width: activityWidth, height: 4.0)), insets: UIEdgeInsets())) + let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleString, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - 20.0 - 22.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: TextNodeCutout(topLeft: CGSize(width: activityWidth, height: 4.0)), insets: UIEdgeInsets())) let contentSize: CGSize let insets: UIEdgeInsets diff --git a/TelegramUI/ListMessageFileItemNode.swift b/TelegramUI/ListMessageFileItemNode.swift index 2e616d2ce9..8874e1034a 100644 --- a/TelegramUI/ListMessageFileItemNode.swift +++ b/TelegramUI/ListMessageFileItemNode.swift @@ -777,7 +777,7 @@ final class ListMessageFileItemNode: ListMessageNode { } case .playbackStatus: if let account = self.account, let applicationContext = account.applicationContext as? TelegramApplicationContext { - applicationContext.mediaManager.playlistControl(.playback(.togglePlayPause)) + applicationContext.mediaManager?.playlistControl(.playback(.togglePlayPause)) } } } diff --git a/TelegramUI/ListMessageSnippetItemNode.swift b/TelegramUI/ListMessageSnippetItemNode.swift index 424b95252e..8de7ad408d 100644 --- a/TelegramUI/ListMessageSnippetItemNode.swift +++ b/TelegramUI/ListMessageSnippetItemNode.swift @@ -286,7 +286,7 @@ final class ListMessageSnippetItemNode: ListMessageNode { let (descriptionNodeLayout, descriptionNodeApply) = descriptionNodeMakeLayout(TextNodeLayoutArguments(attributedString: descriptionText, backgroundColor: nil, maximumNumberOfLines: 3, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 8.0 - params.rightInset - 12.0, height: CGFloat.infinity), alignment: .natural, lineSpacing: 0.3, cutout: nil, insets: UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0))) - let (linkNodeLayout, linkNodeApply) = linkNodeMakeLayout(TextNodeLayoutArguments(attributedString: linkText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 8.0 - params.rightInset - 12.0, height: CGFloat.infinity), alignment: .natural, lineSpacing: 0.3, cutout: isInstantView ? TextNodeCutout(position: .TopLeft, size: CGSize(width: 14.0, height: 8.0)) : nil, insets: UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0))) + let (linkNodeLayout, linkNodeApply) = linkNodeMakeLayout(TextNodeLayoutArguments(attributedString: linkText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 8.0 - params.rightInset - 12.0, height: CGFloat.infinity), alignment: .natural, lineSpacing: 0.3, cutout: isInstantView ? TextNodeCutout(topLeft: CGSize(width: 14.0, height: 8.0)) : nil, insets: UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0))) var instantViewImage: UIImage? if isInstantView { instantViewImage = PresentationResourcesChat.sharedMediaInstantViewIcon(item.theme) diff --git a/TelegramUI/ManagedAudioSession.swift b/TelegramUI/ManagedAudioSession.swift index f0f35957fa..b9f7803486 100644 --- a/TelegramUI/ManagedAudioSession.swift +++ b/TelegramUI/ManagedAudioSession.swift @@ -625,7 +625,6 @@ public final class ManagedAudioSession { case .builtin: resetToBuiltin = true case .speaker: - try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker) if type == .voiceCall { if let routes = AVAudioSession.sharedInstance().availableInputs { for route in routes { @@ -636,6 +635,7 @@ public final class ManagedAudioSession { } } } + try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker) case .headphones: break case let .port(port): diff --git a/TelegramUI/MediaManager.swift b/TelegramUI/MediaManager.swift index 0920c7b6cc..8db78dbe36 100644 --- a/TelegramUI/MediaManager.swift +++ b/TelegramUI/MediaManager.swift @@ -131,7 +131,8 @@ public final class MediaManager: NSObject { super.init() - let combinedPlayersSignal: Signal<(SharedMediaPlayerItemPlaybackState, MediaManagerPlayerType)?, NoError> = combineLatest(self.voiceMediaPlayerState, self.musicMediaPlayerState) |> map { voice, music -> (SharedMediaPlayerItemPlaybackState, MediaManagerPlayerType)? in + let combinedPlayersSignal: Signal<(SharedMediaPlayerItemPlaybackState, MediaManagerPlayerType)?, NoError> = combineLatest(queue: Queue.mainQueue(), self.voiceMediaPlayerState, self.musicMediaPlayerState) + |> map { voice, music -> (SharedMediaPlayerItemPlaybackState, MediaManagerPlayerType)? in if let voice = voice { return (voice, .voice) } else if let music = music { @@ -339,7 +340,7 @@ public final class MediaManager: NSObject { })) - let shouldKeepAudioSession: Signal = combineLatest(self.globalMediaPlayerState |> deliverOnMainQueue, inForeground |> deliverOnMainQueue) + let shouldKeepAudioSession: Signal = combineLatest(queue: Queue.mainQueue(), self.globalMediaPlayerState, inForeground) |> map { stateAndType, inForeground -> Bool in var isPlaying = false if let (state, _) = stateAndType { diff --git a/TelegramUI/NotificationSoundSelection.swift b/TelegramUI/NotificationSoundSelection.swift index 6553e52dea..336c75816a 100644 --- a/TelegramUI/NotificationSoundSelection.swift +++ b/TelegramUI/NotificationSoundSelection.swift @@ -216,7 +216,7 @@ private func playSound(account: Account, sound: PeerMessageSound, defaultSound: return Signal { subscriber in var currentPlayer: AudioPlayerWrapper? var deactivateImpl: (() -> Void)? - let session = account.telegramApplicationContext.mediaManager.audioSession.push(audioSessionType: .play, activate: { _ in + let session = account.telegramApplicationContext.mediaManager?.audioSession.push(audioSessionType: .play, activate: { _ in if let url = Bundle.main.url(forResource: fileNameForNotificationSound(sound, defaultSound: defaultSound), withExtension: "m4a") { currentPlayer = AudioPlayerWrapper(url: url, completed: { deactivateImpl?() @@ -230,10 +230,10 @@ private func playSound(account: Account, sound: PeerMessageSound, defaultSound: return .complete() }) deactivateImpl = { - session.dispose() + session?.dispose() } return ActionDisposable { - session.dispose() + session?.dispose() currentPlayer?.stop() currentPlayer = nil } diff --git a/TelegramUI/OpenChatMessage.swift b/TelegramUI/OpenChatMessage.swift index b4ad146b3c..d8c40751b2 100644 --- a/TelegramUI/OpenChatMessage.swift +++ b/TelegramUI/OpenChatMessage.swift @@ -217,8 +217,10 @@ func openChatMessage(account: Account, message: Message, standalone: Bool, rever dismissInput() present(controller, nil) return true - case .document: - present(ShareController(account: account, subject: .messages([message]), showInChat: nil, externalShare: true, immediateExternalShare: true), nil) + case let .document(file): + let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } + navigationController?.view.window?.rootViewController?.present(DocumentPreviewController(theme: presentationData.theme, strings: presentationData.strings, postbox: account.postbox, file: file), animated: true, completion: nil) + //present(ShareController(account: account, subject: .messages([message]), showInChat: nil, externalShare: true, immediateExternalShare: true), nil) return true case let .audio(file): let location: PeerMessagesPlaylistLocation @@ -245,7 +247,7 @@ func openChatMessage(account: Account, message: Message, standalone: Bool, rever } playerType = (file.isVoice || file.isInstantVideo) ? .voice : .music } - account.telegramApplicationContext.mediaManager.setPlaylist(PeerMessagesMediaPlaylist(postbox: account.postbox, network: account.network, location: location), type: playerType) + account.telegramApplicationContext.mediaManager?.setPlaylist(PeerMessagesMediaPlaylist(postbox: account.postbox, network: account.network, location: location), type: playerType) return true case let .gallery(gallery): dismissInput() diff --git a/TelegramUI/OpenUrl.swift b/TelegramUI/OpenUrl.swift index e4bb90f7f3..8a401f310d 100644 --- a/TelegramUI/OpenUrl.swift +++ b/TelegramUI/OpenUrl.swift @@ -440,10 +440,10 @@ public func openExternalUrl(account: Account, context: OpenURLContext = .generic navigationController.view.window?.rootViewController?.dismiss(animated: true, completion: nil) navigateToChatController(navigationController: navigationController, account: account, chatLocation: .peer(peerId)) } - case .withBotStartPayload: + case let .withBotStartPayload(payload): if let navigationController = navigationController { navigationController.view.window?.rootViewController?.dismiss(animated: true, completion: nil) - navigateToChatController(navigationController: navigationController, account: account, chatLocation: .peer(peerId)) + navigateToChatController(navigationController: navigationController, account: account, chatLocation: .peer(peerId), botStart: payload) } } }, present: { c, a in diff --git a/TelegramUI/OverlayPlayerControllerNode.swift b/TelegramUI/OverlayPlayerControllerNode.swift index 9d727056fc..a8acd66f85 100644 --- a/TelegramUI/OverlayPlayerControllerNode.swift +++ b/TelegramUI/OverlayPlayerControllerNode.swift @@ -75,7 +75,7 @@ final class OverlayPlayerControllerNode: ViewControllerTracingNode, UIGestureRec self.contentNode = ASDisplayNode() - self.controlsNode = OverlayPlayerControlsNode(postbox: account.postbox, theme: self.presentationData.theme, status: account.telegramApplicationContext.mediaManager.musicMediaPlayerState) + self.controlsNode = OverlayPlayerControlsNode(postbox: account.postbox, theme: self.presentationData.theme, status: account.telegramApplicationContext.mediaManager!.musicMediaPlayerState) self.historyBackgroundNode = ASDisplayNode() self.historyBackgroundNode.isLayerBacked = true @@ -142,7 +142,7 @@ final class OverlayPlayerControllerNode: ViewControllerTracingNode, UIGestureRec self.controlsNode.control = { [weak self] action in if let strongSelf = self { - strongSelf.account.telegramApplicationContext.mediaManager.playlistControl(action, type: strongSelf.type) + strongSelf.account.telegramApplicationContext.mediaManager?.playlistControl(action, type: strongSelf.type) } } diff --git a/TelegramUI/PeerMediaCollectionController.swift b/TelegramUI/PeerMediaCollectionController.swift index 2172d475b7..98cdfe56f9 100644 --- a/TelegramUI/PeerMediaCollectionController.swift +++ b/TelegramUI/PeerMediaCollectionController.swift @@ -462,30 +462,32 @@ public class PeerMediaCollectionController: TelegramController { self.displayNode = PeerMediaCollectionControllerNode(account: self.account, peerId: self.peerId, messageId: self.messageId, controllerInteraction: self.controllerInteraction!, interfaceInteraction: self.interfaceInteraction!, navigationBar: self.navigationBar, requestDeactivateSearch: { [weak self] in self?.deactivateSearch() }) - - self.galleryHiddenMesageAndMediaDisposable.set(self.account.telegramApplicationContext.mediaManager.galleryHiddenMediaManager.hiddenIds().start(next: { [weak self] ids in - if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction { - var messageIdAndMedia: [MessageId: [Media]] = [:] - - for id in ids { - if case let .chat(messageId, media) = id { - messageIdAndMedia[messageId] = [media] + + if let mediaManager = self.account.telegramApplicationContext.mediaManager { + self.galleryHiddenMesageAndMediaDisposable.set(mediaManager.galleryHiddenMediaManager.hiddenIds().start(next: { [weak self] ids in + if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction { + var messageIdAndMedia: [MessageId: [Media]] = [:] + + for id in ids { + if case let .chat(messageId, media) = id { + messageIdAndMedia[messageId] = [media] + } } - } - - //if controllerInteraction.hiddenMedia != messageIdAndMedia { - controllerInteraction.hiddenMedia = messageIdAndMedia - - strongSelf.mediaCollectionDisplayNode.historyNode.forEachItemNode { itemNode in - if let itemNode = itemNode as? GridMessageItemNode { - itemNode.updateHiddenMedia() - } else if let itemNode = itemNode as? ListMessageNode { - itemNode.updateHiddenMedia() + + //if controllerInteraction.hiddenMedia != messageIdAndMedia { + controllerInteraction.hiddenMedia = messageIdAndMedia + + strongSelf.mediaCollectionDisplayNode.historyNode.forEachItemNode { itemNode in + if let itemNode = itemNode as? GridMessageItemNode { + itemNode.updateHiddenMedia() + } else if let itemNode = itemNode as? ListMessageNode { + itemNode.updateHiddenMedia() + } } + //} } - //} - } - })) + })) + } self.ready.set(combineLatest(self.mediaCollectionDisplayNode.historyNode.historyState.get(), self._peerReady.get()) |> map { $1 }) diff --git a/TelegramUI/PhotoResources.swift b/TelegramUI/PhotoResources.swift index 4ee3ea1c4a..4fd3c9e3df 100644 --- a/TelegramUI/PhotoResources.swift +++ b/TelegramUI/PhotoResources.swift @@ -540,17 +540,15 @@ func rawMessagePhoto(postbox: Postbox, photoReference: ImageMediaReference) -> S } } -func chatMessagePhoto(postbox: Postbox, photoReference: ImageMediaReference) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { - return chatMessagePhotoInternal(postbox: postbox, photoReference: photoReference) +public func chatMessagePhoto(postbox: Postbox, photoReference: ImageMediaReference) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { + return chatMessagePhotoInternal(photoData: chatMessagePhotoDatas(postbox: postbox, photoReference: photoReference)) |> map { _, generate in return generate } } -func chatMessagePhotoInternal(postbox: Postbox, photoReference: ImageMediaReference) -> Signal<(() -> CGSize?, (TransformImageArguments) -> DrawingContext?), NoError> { - let signal = chatMessagePhotoDatas(postbox: postbox, photoReference: photoReference) - - return signal +public func chatMessagePhotoInternal(photoData: Signal<(Data?, Data?, Bool), NoError>) -> Signal<(() -> CGSize?, (TransformImageArguments) -> DrawingContext?), NoError> { + return photoData |> map { (thumbnailData, fullSizeData, fullSizeComplete) in return ({ return nil @@ -1432,7 +1430,7 @@ func chatMessagePhotoStatus(account: Account, messageId: MessageId, photoReferen } } -func chatMessagePhotoInteractiveFetched(account: Account, photoReference: ImageMediaReference) -> Signal { +public func chatMessagePhotoInteractiveFetched(account: Account, photoReference: ImageMediaReference) -> Signal { if let largestRepresentation = largestRepresentationForPhoto(photoReference.media) { return fetchedMediaResource(postbox: account.postbox, reference: photoReference.resourceReference(largestRepresentation.resource), statsCategory: .image) } else { diff --git a/TelegramUI/RadialStatusNode.swift b/TelegramUI/RadialStatusNode.swift index 0d10c6418d..69e8d9822f 100644 --- a/TelegramUI/RadialStatusNode.swift +++ b/TelegramUI/RadialStatusNode.swift @@ -1,7 +1,7 @@ import Foundation import AsyncDisplayKit -enum RadialStatusNodeState: Equatable { +public enum RadialStatusNodeState: Equatable { case none case download(UIColor) case play(UIColor) @@ -11,7 +11,7 @@ enum RadialStatusNodeState: Equatable { case customIcon(UIImage) case secretTimeout(color: UIColor, icon: UIImage?, beginTime: Double, timeout: Double) - static func ==(lhs: RadialStatusNodeState, rhs: RadialStatusNodeState) -> Bool { + public static func ==(lhs: RadialStatusNodeState, rhs: RadialStatusNodeState) -> Bool { switch lhs { case .none: if case .none = rhs { @@ -99,13 +99,13 @@ enum RadialStatusNodeState: Equatable { node.progress = value return node } - case let .secretTimeout(color, icon, beginTime, timeout): - return RadialStatusSecretTimeoutContentNode(color: color, beginTime: beginTime, timeout: timeout, icon: icon) + case let .secretTimeout(color, icon, beginTime, timeout): + return RadialStatusSecretTimeoutContentNode(color: color, beginTime: beginTime, timeout: timeout, icon: icon) } } } -final class RadialStatusNode: ASControlNode { +public final class RadialStatusNode: ASControlNode { private var backgroundNodeColor: UIColor private(set) var state: RadialStatusNodeState = .none @@ -114,13 +114,13 @@ final class RadialStatusNode: ASControlNode { private var contentNode: RadialStatusContentNode? private var nextContentNode: RadialStatusContentNode? - init(backgroundNodeColor: UIColor) { + public init(backgroundNodeColor: UIColor) { self.backgroundNodeColor = backgroundNodeColor super.init() } - func transitionToState(_ state: RadialStatusNodeState, animated: Bool = true, completion: @escaping () -> Void) { + public func transitionToState(_ state: RadialStatusNodeState, animated: Bool = true, completion: @escaping () -> Void) { if self.state != state { self.state = state @@ -221,7 +221,7 @@ final class RadialStatusNode: ASControlNode { } } - override func layout() { + override public func layout() { self.backgroundNode?.frame = self.bounds if let contentNode = self.contentNode { contentNode.frame = self.bounds diff --git a/TelegramUI/ReplyAccessoryPanelNode.swift b/TelegramUI/ReplyAccessoryPanelNode.swift index 836e5bb556..e0a38d8b3c 100644 --- a/TelegramUI/ReplyAccessoryPanelNode.swift +++ b/TelegramUI/ReplyAccessoryPanelNode.swift @@ -13,8 +13,8 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode { let closeButton: ASButtonNode let lineNode: ASImageNode - let titleNode: ASTextNode - let textNode: ASTextNode + let titleNode: ImmediateTextNode + let textNode: ImmediateTextNode let imageNode: TransformImageNode var theme: PresentationTheme @@ -34,13 +34,11 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode { self.lineNode.displaysAsynchronously = false self.lineNode.image = PresentationResourcesChat.chatInputPanelVerticalSeparatorLineImage(theme) - self.titleNode = ASTextNode() - self.titleNode.truncationMode = .byTruncatingTail + self.titleNode = ImmediateTextNode() self.titleNode.maximumNumberOfLines = 1 self.titleNode.displaysAsynchronously = false - self.textNode = ASTextNode() - self.textNode.truncationMode = .byTruncatingTail + self.textNode = ImmediateTextNode() self.textNode.maximumNumberOfLines = 1 self.textNode.displaysAsynchronously = false @@ -216,10 +214,10 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode { } self.imageNode.frame = CGRect(origin: CGPoint(x: leftInset + 9.0, y: 8.0), size: CGSize(width: 35.0, height: 35.0)) - let titleSize = self.titleNode.measure(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset - imageTextInset, height: bounds.size.height)) + let titleSize = self.titleNode.updateLayout(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset - imageTextInset, height: bounds.size.height)) self.titleNode.frame = CGRect(origin: CGPoint(x: leftInset + textLineInset + imageTextInset, y: 7.0), size: titleSize) - let textSize = self.textNode.measure(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset - imageTextInset, height: bounds.size.height)) + let textSize = self.textNode.updateLayout(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset - imageTextInset, height: bounds.size.height)) self.textNode.frame = CGRect(origin: CGPoint(x: leftInset + textLineInset + imageTextInset, y: 25.0), size: textSize) } diff --git a/TelegramUI/SecretMediaPreviewController.swift b/TelegramUI/SecretMediaPreviewController.swift index db8fb19ab5..db2a9651d0 100644 --- a/TelegramUI/SecretMediaPreviewController.swift +++ b/TelegramUI/SecretMediaPreviewController.swift @@ -158,13 +158,16 @@ public final class SecretMediaPreviewController: ViewController { } })) - self.hiddenMediaManagerIndex = account.telegramApplicationContext.mediaManager.galleryHiddenMediaManager.addSource(self._hiddenMedia.get() |> map { messageIdAndMedia in - if let (messageId, media) = messageIdAndMedia { - return .chat(messageId, media) - } else { - return nil - } - }) + if let mediaManager = account.telegramApplicationContext.mediaManager { + self.hiddenMediaManagerIndex = mediaManager.galleryHiddenMediaManager.addSource(self._hiddenMedia.get() + |> map { messageIdAndMedia in + if let (messageId, media) = messageIdAndMedia { + return .chat(messageId, media) + } else { + return nil + } + }) + } self.screenCaptureEventsDisposable = (screenCaptureEvents() |> deliverOnMainQueue).start(next: { [weak self] _ in @@ -181,8 +184,8 @@ public final class SecretMediaPreviewController: ViewController { deinit { self.disposable.dispose() self.markMessageAsConsumedDisposable.dispose() - if let hiddenMediaManagerIndex = self.hiddenMediaManagerIndex { - self.account.telegramApplicationContext.mediaManager.galleryHiddenMediaManager.removeSource(hiddenMediaManagerIndex) + if let hiddenMediaManagerIndex = self.hiddenMediaManagerIndex, let mediaManager = self.account.telegramApplicationContext.mediaManager { + mediaManager.galleryHiddenMediaManager.removeSource(hiddenMediaManagerIndex) } self.screenCaptureEventsDisposable?.dispose() } diff --git a/TelegramUI/TelegramApplicationContext.swift b/TelegramUI/TelegramApplicationContext.swift index 82620bf5c7..6c514e1d41 100644 --- a/TelegramUI/TelegramApplicationContext.swift +++ b/TelegramUI/TelegramApplicationContext.swift @@ -55,7 +55,7 @@ public final class TelegramApplicationContext { let fetchManager: FetchManager public var callManager: PresentationCallManager? - public let mediaManager: MediaManager + public let mediaManager: MediaManager? let locationManager: DeviceLocationManager? public let liveLocationManager: LiveLocationManager? @@ -106,7 +106,11 @@ public final class TelegramApplicationContext { private var storedPassword: (String, CFAbsoluteTime, SwiftSignalKit.Timer)? public init(applicationBindings: TelegramApplicationBindings, accountManager: AccountManager, account: Account?, initialPresentationDataAndSettings: InitialPresentationDataAndSettings, postbox: Postbox) { - self.mediaManager = MediaManager(postbox: postbox, inForeground: applicationBindings.applicationInForeground) + if account != nil { + self.mediaManager = MediaManager(postbox: postbox, inForeground: applicationBindings.applicationInForeground) + } else { + self.mediaManager = nil + } if applicationBindings.isMainApp { self.locationManager = DeviceLocationManager(queue: Queue.mainQueue()) @@ -218,7 +222,7 @@ public final class TelegramApplicationContext { } public func attachOverlayMediaController(_ controller: OverlayMediaController) { - self.mediaManager.overlayMediaManager.attachOverlayMediaController(controller) + self.mediaManager?.overlayMediaManager.attachOverlayMediaController(controller) } public func storeSecureIdPassword(password: String) { diff --git a/TelegramUI/TelegramController.swift b/TelegramUI/TelegramController.swift index fc9db3dd2c..7765630584 100644 --- a/TelegramUI/TelegramController.swift +++ b/TelegramUI/TelegramController.swift @@ -88,8 +88,8 @@ public class TelegramController: ViewController { super.init(navigationBarPresentationData: navigationBarPresentationData) - if case .none = mediaAccessoryPanelVisibility {} else { - self.mediaStatusDisposable = (account.telegramApplicationContext.mediaManager.globalMediaPlayerState + if case .none = mediaAccessoryPanelVisibility {} else if let mediaManager = account.telegramApplicationContext.mediaManager { + self.mediaStatusDisposable = (mediaManager.globalMediaPlayerState |> deliverOnMainQueue).start(next: { [weak self] playlistStateAndType in if let strongSelf = self { if !arePlaylistItemsEqual(strongSelf.playlistStateAndType?.0, playlistStateAndType?.0.item) || @@ -379,8 +379,12 @@ public class TelegramController: ViewController { transition.updateFrame(layer: mediaAccessoryPanel.layer, frame: panelFrame) mediaAccessoryPanel.updateLayout(size: panelFrame.size, transition: transition) mediaAccessoryPanel.containerNode.headerNode.playbackItem = item - mediaAccessoryPanel.containerNode.headerNode.playbackStatus = self.account.telegramApplicationContext.mediaManager.globalMediaPlayerState |> map { state in - return state?.0.status ?? MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .paused) + + if let mediaManager = self.account.telegramApplicationContext.mediaManager { + mediaAccessoryPanel.containerNode.headerNode.playbackStatus = mediaManager.globalMediaPlayerState + |> map { state in + return state?.0.status ?? MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .paused) + } } } else { if let (mediaAccessoryPanel, _) = self.mediaAccessoryPanel { @@ -398,7 +402,7 @@ public class TelegramController: ViewController { mediaAccessoryPanel.containerNode.headerNode.displayScrubber = type != .voice mediaAccessoryPanel.close = { [weak self] in if let strongSelf = self, let (_, _, type) = strongSelf.playlistStateAndType { - strongSelf.account.telegramApplicationContext.mediaManager.setPlaylist(nil, type: type) + strongSelf.account.telegramApplicationContext.mediaManager?.setPlaylist(nil, type: type) } } mediaAccessoryPanel.toggleRate = { @@ -424,12 +428,12 @@ public class TelegramController: ViewController { return } - strongSelf.account.telegramApplicationContext.mediaManager.playlistControl(.setBaseRate(baseRate), type: type) + strongSelf.account.telegramApplicationContext.mediaManager?.playlistControl(.setBaseRate(baseRate), type: type) }) } mediaAccessoryPanel.togglePlayPause = { [weak self] in if let strongSelf = self, let (_, _, type) = strongSelf.playlistStateAndType { - strongSelf.account.telegramApplicationContext.mediaManager.playlistControl(.playback(.togglePlayPause), type: type) + strongSelf.account.telegramApplicationContext.mediaManager?.playlistControl(.playback(.togglePlayPause), type: type) } } mediaAccessoryPanel.tapAction = { [weak self] in @@ -456,8 +460,11 @@ public class TelegramController: ViewController { self.mediaAccessoryPanel = (mediaAccessoryPanel, type) mediaAccessoryPanel.updateLayout(size: panelFrame.size, transition: .immediate) mediaAccessoryPanel.containerNode.headerNode.playbackItem = item - mediaAccessoryPanel.containerNode.headerNode.playbackStatus = self.account.telegramApplicationContext.mediaManager.globalMediaPlayerState |> map { state in - return state?.0.status ?? MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .paused) + if let mediaManager = self.account.telegramApplicationContext.mediaManager { + mediaAccessoryPanel.containerNode.headerNode.playbackStatus = mediaManager.globalMediaPlayerState + |> map { state in + return state?.0.status ?? MediaPlayerStatus(generationTimestamp: 0.0, duration: 0.0, dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .paused) + } } mediaAccessoryPanel.animateIn(transition: transition) } diff --git a/TelegramUI/TelegramInitializeLegacyComponents.swift b/TelegramUI/TelegramInitializeLegacyComponents.swift index 6696dca29b..8f8a08a8cf 100644 --- a/TelegramUI/TelegramInitializeLegacyComponents.swift +++ b/TelegramUI/TelegramInitializeLegacyComponents.swift @@ -223,14 +223,14 @@ private final class LegacyComponentsGlobalsProviderImpl: NSObject, LegacyCompone default: convertedType = .play } - let disposable = legacyAccount.telegramApplicationContext.mediaManager.audioSession.push(audioSessionType: convertedType, once: true, activate: { _ in + let disposable = legacyAccount.telegramApplicationContext.mediaManager?.audioSession.push(audioSessionType: convertedType, once: true, activate: { _ in }, deactivate: { interrupted?() return .complete() }) return SBlockDisposable(block: { - disposable.dispose() + disposable?.dispose() }) } return nil diff --git a/TelegramUI/TransformImageNode.swift b/TelegramUI/TransformImageNode.swift index 238fd7f167..5ed6c36c8d 100644 --- a/TelegramUI/TransformImageNode.swift +++ b/TelegramUI/TransformImageNode.swift @@ -37,7 +37,7 @@ public class TransformImageNode: ASDisplayNode { } } - func setSignal(_ signal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>, dispatchOnDisplayLink: Bool = true) { + public func setSignal(_ signal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>, dispatchOnDisplayLink: Bool = true) { let argumentsPromise = self.argumentsPromise let result = combineLatest(signal, argumentsPromise.get()) diff --git a/TelegramUI/UniversalVideoCalleryItem.swift b/TelegramUI/UniversalVideoCalleryItem.swift index f905fb28b7..c804893cac 100644 --- a/TelegramUI/UniversalVideoCalleryItem.swift +++ b/TelegramUI/UniversalVideoCalleryItem.swift @@ -255,7 +255,11 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { self.footerContentNode.scrubberView = nil } - let videoNode = UniversalVideoNode(postbox: item.account.postbox, audioSession: item.account.telegramApplicationContext.mediaManager.audioSession, manager: item.account.telegramApplicationContext.mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: item.content, priority: .gallery) + guard let mediaManager = item.account.telegramApplicationContext.mediaManager else { + preconditionFailure() + } + + let videoNode = UniversalVideoNode(postbox: item.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: item.content, priority: .gallery) let videoSize = CGSize(width: item.content.dimensions.width * 2.0, height: item.content.dimensions.height * 2.0) videoNode.updateLayout(size: videoSize, transition: .immediate) videoNode.ownsContentNodeUpdated = { [weak self] value in @@ -439,7 +443,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { let transform = CATransform3DScale(videoNode.layer.transform, transformedFrame.size.width / videoNode.layer.bounds.size.width, transformedFrame.size.height / videoNode.layer.bounds.size.height, 1.0) videoNode.layer.animate(from: NSValue(caTransform3D: transform), to: NSValue(caTransform3D: videoNode.layer.transform), keyPath: "transform", timingFunction: kCAMediaTimingFunctionSpring, duration: 0.25) - self.account.telegramApplicationContext.mediaManager.setOverlayVideoNode(nil) + self.account.telegramApplicationContext.mediaManager?.setOverlayVideoNode(nil) } else { var transformedFrame = node.0.view.convert(node.0.view.bounds, to: videoNode.view) let transformedSuperFrame = node.0.view.convert(node.0.view.bounds, to: videoNode.view.superview) @@ -696,9 +700,9 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { if let item = self.item, let _ = self.videoNode { let account = self.account let baseNavigationController = self.baseNavigationController() - let mediaManager = self.account.telegramApplicationContext.mediaManager + let mediaManager = self.account.telegramApplicationContext.mediaManager! var expandImpl: (() -> Void)? - let overlayNode = OverlayUniversalVideoNode(account: self.account, audioSession: self.account.telegramApplicationContext.mediaManager.audioSession, manager: self.account.telegramApplicationContext.mediaManager.universalVideoManager, content: item.content, expand: { + let overlayNode = OverlayUniversalVideoNode(account: self.account, audioSession: self.account.telegramApplicationContext.mediaManager!.audioSession, manager: self.account.telegramApplicationContext.mediaManager!.universalVideoManager, content: item.content, expand: { expandImpl?() }, close: { [weak mediaManager] in mediaManager?.setOverlayVideoNode(nil) @@ -734,7 +738,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { break } } - account.telegramApplicationContext.mediaManager.setOverlayVideoNode(overlayNode) + account.telegramApplicationContext.mediaManager?.setOverlayVideoNode(overlayNode) if overlayNode.supernode != nil { self.beginCustomDismiss() self.animateOut(toOverlay: overlayNode, completion: { [weak self] in